j1_template_mde 2018.4.15 → 2018.4.16

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/_includes/themes/j1/layouts/content_generator_blog_archive.html +3 -3
  3. data/_includes/themes/j1/layouts/layout_shim_generator.html +4 -0
  4. data/_includes/themes/j1/modules/navigator/generator.html +4 -4
  5. data/_includes/themes/j1/modules/navigator/procedures/sidebar.proc +174 -127
  6. data/lib/j1/version.rb +1 -1
  7. data/lib/j1_app.rb +4 -1
  8. data/lib/j1_app/j1_auth_manager/auth_manager.previous.rb +939 -0
  9. data/lib/j1_app/j1_auth_manager/auth_manager.rb +386 -214
  10. data/lib/j1_app/j1_auth_manager/config.rb +103 -66
  11. data/lib/j1_app/j1_auth_manager/helpers.rb +22 -14
  12. data/lib/j1_app/j1_auth_manager/views/auth_manager_ui.erb +7 -2
  13. data/lib/j1_app/omniauth/strategies/_unused/doumart_patreon.rb +75 -0
  14. data/lib/j1_app/omniauth/strategies/_unused/my_patreon.rb +78 -0
  15. data/lib/j1_app/omniauth/strategies/_unused/patreon.v1.rb +50 -0
  16. data/lib/j1_app/omniauth/strategies/_unused/patreon.v2-v1.rb +82 -0
  17. data/lib/j1_app/omniauth/strategies/_unused/patreon.v2.rb +79 -0
  18. data/lib/starter_web/Gemfile +185 -168
  19. data/lib/starter_web/_config.yml +85 -69
  20. data/lib/starter_web/_data/j1_resources.yml +15 -0
  21. data/lib/starter_web/_data/modules/j1_navigator.yml +79 -12
  22. data/lib/starter_web/_rack/Guardfile +75 -0
  23. data/lib/starter_web/assets/data/authclient.html +10 -7
  24. data/lib/starter_web/assets/data/banner.html +127 -127
  25. data/lib/starter_web/assets/images/patreon/premium-content-460x200.png +0 -0
  26. data/lib/starter_web/assets/images/patreon/scalable/{Premium-content.psd → premium-content.psd} +0 -0
  27. data/lib/starter_web/assets/images/patreon/scalable/value-content.psd +0 -0
  28. data/lib/starter_web/assets/images/patreon/value-content-460x200.png +0 -0
  29. data/lib/starter_web/assets/themes/j1/core/css/theme_extensions.css +2 -2
  30. data/lib/starter_web/assets/themes/j1/core/css/theme_extensions.min.css +1 -1
  31. data/lib/starter_web/assets/themes/j1/core/css/uno.css +2 -2
  32. data/lib/starter_web/assets/themes/j1/core/css/uno.min.css +1 -1
  33. data/lib/starter_web/assets/themes/j1/core/js/adapter/navigator.js +66 -11
  34. data/lib/starter_web/assets/themes/j1/core/js/adapter/navigator.js.failed +797 -0
  35. data/lib/starter_web/assets/themes/j1/core/js/adapter/template.js +26 -7
  36. data/lib/starter_web/assets/themes/j1/extensions/livereload/LICENSE +20 -0
  37. data/lib/starter_web/assets/themes/j1/extensions/livereload/README.md +249 -0
  38. data/lib/starter_web/assets/themes/j1/extensions/livereload/js/livereload.js +1951 -0
  39. data/lib/starter_web/assets/themes/j1/extensions/livereload/js/livereload.min.js +1 -0
  40. data/lib/starter_web/assets/themes/j1/extensions/patreon/patreon.widget.button.html +21 -0
  41. data/lib/starter_web/package.json +14 -5
  42. data/lib/starter_web/pages/public/about/become_a_patron.adoc +1 -1
  43. data/lib/starter_web/pages/public/blog/navigator/archive.html +0 -1
  44. metadata +19 -4
  45. data/lib/starter_web/assets/images/patreon/premium-content-420x200.png +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: bb1d836040863af7c2f5bfcb17e0897d7e8559b0
4
- data.tar.gz: e85d5a184f9521cef89b62fb792707f03199fda6
3
+ metadata.gz: 486d7834679c80fb7919eaa3203184f4891c9d30
4
+ data.tar.gz: e0e75259ef112f056c8b0b84032cd64a156d76b0
5
5
  SHA512:
6
- metadata.gz: a6051cea6b49417aa81ca45fb3e86ed8bbf3d31da2c4137626bb17938b9ae6540ee434e313f4cb08d24056147f6ea80fb3985a051fc6ee0e6f8037ad07b574eb
7
- data.tar.gz: 1eabe6ca724e2e67373d582e415cbae9faf15711485d7824292030dcaeca267d9c43af03134dcbe9b3dd33487da10069197a1cd0be1765c6c139c3a9885d71a3
6
+ metadata.gz: '08a86d2f7a90d49aeb01c012e33986b85ec312ab8ac092396555291a65ba66e08ae00154c16c8eee86452dac631bc421fde5e5cb4ec8f02d65cd46d4ea5c1d20'
7
+ data.tar.gz: 6920df9be2589b625a5c798b467c51b30ff37bcc7afdad50af6faf26d780d75b8d5c6260314d90cd171dd8d3b1b4d298e8b42ea8911fd28c9c5619412f6c5933
@@ -65,12 +65,12 @@
65
65
  <div id="blog_navigator" class="row">
66
66
  <div class="col-md-12" role="main">
67
67
 
68
- <div id="article_navigator">
68
+ <div id="article_navigator">
69
69
 
70
70
  {% include {{get_page_path}} mode='absolute' %}
71
- {% capture navigator_path%}{{page_path}}/navigator{% endcapture %}
72
-
71
+ {% capture navigator_path%}{{page_path}}{% endcapture %}
73
72
  {% capture archive_path %}{{navigator_path}}/archive{% endcapture %}
73
+
74
74
  {% capture date_view %}{{archive_path}}/dateview/{% endcapture %}
75
75
  {% capture category_view %}{{archive_path}}/categoryview/{% endcapture %}
76
76
  {% capture tag_view %}{{archive_path}}/tagview/{% endcapture %}
@@ -102,4 +102,8 @@
102
102
  document.querySelector("head").appendChild(e);
103
103
  }
104
104
 
105
+ // jadams, 2019-01-14: Test to declare SideBar variables
106
+ // var $this;
107
+ // var html;
108
+
105
109
  </script>
@@ -18,7 +18,7 @@
18
18
  # -----------------------------------------------------------------------------
19
19
  {% endcomment %}
20
20
 
21
- {% comment %} Liquid procedures
21
+ {% comment %} Liquid procedures
22
22
  -------------------------------------------------------------------------------- {% endcomment %}
23
23
  {% include themes/{{site.template.name}}/procedures/global/setup.proc %}
24
24
  {% capture select_color %}themes/{{site.template.name}}/procedures/global/select_color.proc{% endcapture %}
@@ -81,7 +81,7 @@
81
81
  {% if nav_fixed %}
82
82
  {% assign nav_bar_fixed = 'navbar-fixed' %}
83
83
  {% if nav_style == 'overlay' %} {% assign nav_bar_style = 'navbar-transparent' %} {% endif %}
84
- {% endif %}
84
+ {% endif %}
85
85
 
86
86
  {% if nav_color == 'light' %}
87
87
  {% assign nav_bar_color = 'light' %}
@@ -90,9 +90,9 @@
90
90
  {% capture menu_id %}{{nav_id}}_menu{% endcapture %}
91
91
  {% capture nav_bar_defaults %}navbar navigator navbar-expand-{{nav_expand}} navbar-default{% endcapture %}
92
92
 
93
- {% comment %} Main
94
- -------------------------------------------------------------------------------- {% endcomment %}
95
93
 
94
+ {% comment %} Main
95
+ -------------------------------------------------------------------------------- {% endcomment %}
96
96
  <!-- [INFO ] [j1.modules.navigator.generator.html ] [check for topsearch] -->
97
97
  {% if topsearch_options.enabled %}
98
98
  <!-- [INFO ] [j1.modules.navigator.generator.html ] [start processing: topsearch] -->
@@ -23,7 +23,7 @@
23
23
  {% assign sidebar_options = include.options %}
24
24
 
25
25
 
26
- {% comment %} Liquid procedures
26
+ {% comment %} Liquid procedures
27
27
  -------------------------------------------------------------------------------- {% endcomment %}
28
28
  {% capture select_color %}themes/{{site.template.name}}/procedures/global/select_color.proc{% endcapture %}
29
29
  {% capture select_icon_size %}themes/{{site.template.name}}/procedures/global/select_icon_size.proc{% endcapture %}
@@ -34,7 +34,9 @@
34
34
 
35
35
  {% comment %} Set config files
36
36
  ------------------------------------------------------------------------------ {% endcomment %}
37
- {% assign theme_switcher = site.data.modules.j1_theme_switcher %}
37
+ {% assign navigator_config = site.data.modules.j1_navigator %}
38
+ {% assign sidebar_config = navigator_config.nav_sidebar %}
39
+ {% assign theme_switcher = site.data.modules.j1_theme_switcher %}
38
40
 
39
41
 
40
42
  {% comment %} Set sidebar properties
@@ -58,139 +60,184 @@
58
60
  {% assign icon_size = size %}
59
61
 
60
62
 
61
- {% comment %} Main
63
+ {% comment %} Main
62
64
  -------------------------------------------------------------------------------- {% endcomment %}
63
65
 
64
- <!-- [INFO ] [j1.modules.navigator.sidebar.proc ] [start processing: sidebar] -->
66
+ <!-- [INFO ] [j1.modules.navigator.sidebar.proc ] [Start processing: sidebar] -->
65
67
  <div id="mod_sidebar" class="side">
66
- <a href="#" class="close-side"><i class="{{icon_family}} {{icon_family}}-{{close_icon}} {{icon_size}}" {{icon_color}}></i></a>
67
-
68
- {% if display_user_info %}
69
-
70
- <!-- [INFO ] [j1.modules.navigator.sidebar.proc ] [theme manager detected: collect|add user details from /info endpoint] -->
71
- <script>
72
- $(document).ready(function() {
73
- var logger;
74
- var user_data = {};
75
- var dataSet = [];
76
- var logText;
77
-
78
- logger = log4javascript.getLogger('j1.SideBar');
79
-
80
- // Set|Detect J1 App status
81
- if ( j1.existsCookie( 'j1.web.session' ) ) {
82
- // Call middleware info endpoint to return current user state
83
- function load_user_details() {
84
- return $.ajax({
85
- url: '/status',
86
- success: function (data) {
87
- if (typeof data == 'string') {
88
- JSON.parse(data)
89
- }
90
- if (typeof data == 'object') {
91
- data
92
- }
93
- }
94
- })
95
- };
96
- // Add|Place data when collected
97
- $.when( load_user_details() ).done (
98
- function( response ) {
99
- var json_data = JSON.stringify(response);
100
- var user_state = JSON.parse(json_data);
101
- var user = user_state.user;
102
- var state = user_state.status;
103
- var provider = user_state.provider;
104
- var permissions = user_state.permissions;
105
-
106
- logger.info('JSON data: ' + json_data);
107
-
108
- $("#display_user_details").find('.details-user').text('User: ' + user);
109
- $("#display_user_details").find('.details-provider').text('Provider: ' + provider);
110
- $("#display_user_details").find('.details-state').text('State: ' + state);
111
- $("#display_user_details").find('.details-permissions').text('Permissions: ' + permissions);
112
- }); // end load_user_data
113
- } else {
114
- logger.info('Site detected in state: web');
115
- $("#display_user_details").find('.details-user').text('User: n/a');
116
- $("#display_user_details").find('.details-provider').text('Provider: n/a');
117
- $("#display_user_details").find('.details-state').text('State: n/a');
118
- $("#display_user_details").find('.details-permissions').text('Permissions: n/a');
119
- }
120
- });
121
- </script>
122
-
123
- <div class="widget">
124
- <h4 class="heading">User Info</h4>
125
- <ul id="display_user_details" class="link">
126
- <li><a class="details-user" href="#">User: n/a</a></li>
127
- <li><a class="details-provider" href="#">Provider: n/a</a></li>
128
- <li><a class="details-state" href="#">State: n/a</a></li>
129
- <li><a class="details-permissions" href="#">Profile: n/a</a></li>
130
- </ul>
131
- </div>
68
+ <a href="#" class="close-side"><i class="{{icon_family}} {{icon_family}}-{{close_icon}} mdi-48px" {{icon_color}}></i></a>
132
69
 
133
- {% endif %}
134
-
135
- {% if display_theme %}
136
- <div class="widget">
137
- <h4 class="heading">Theme Info</h4>
138
- <ul id="display_theme_details" class="link">
139
- <li><a href="#">Author: Jekyll-One</a></li>
140
- <li><a href="http://getbootstrap.com/" target="_blank">Version: 4</a></li>
141
- </ul>
142
- </div>
143
-
144
- <!-- [INFO ] [j1.modules.navigator.sidebar.proc ] [start processing: theme manager] -->
145
- {% if theme_switcher.enabled %}
146
- <!-- [INFO ] [j1.modules.navigator.sidebar.proc ] [theme manager detected: add add bootstrap theme from cookie] -->
147
- <script>
148
- var j1_user_state = {};
149
- var user_state_detected;
150
- var themeName;
151
- var themeNameHeadline;
152
-
153
- // Read J1 UserState cookie
154
- user_state_detected = j1.existsCookie ( 'j1.user.state' );
155
- if ( user_state_detected ) {
156
- j1_user_state = j1.getUserStateCookie();
157
- themeName = j1_user_state.theme_name;
158
- } else {
159
- themeName = 'J1 Default';
160
- }
161
- var themeNameItem = '<li id="theme_name"><a href="{{theme_switcher.previewPage}}">Theme: ' + themeName + '</a></li>';
162
- $("#display_theme_details").prepend(themeNameItem);
163
- </script>
164
- {% else %}
165
- <script>
166
- <!-- [INFO ] [j1.modules.navigator.sidebar.proc ] [no theme manager detected: add bootstrap theme statically]
167
- var themeNameItem = '<li id="theme_name"><a href="{{theme_switcher.previewPage}}">Theme: Default</a></li>';
168
- $("#display_theme_details").prepend(themeNameItem);
169
- </script>
170
- {% endif %}
171
- <!-- [INFO ] [j1.modules.navigator.sidebar.proc ] [end processing: theme manager] -->
172
- {% endif %}
173
-
174
- <!-- [INFO ] [j1.modules.navigator.sidebar.proc ] [start processing: sidebar boxes] -->
175
- {% for boxes in navigator_config.nav_sidebar.boxes %}
70
+ {% for boxes in sidebar_config.boxes %}
176
71
  {% for box in boxes %}
177
- {% if box[0] == 'box' %}
178
- <div class="widget">
179
- <h4 class="heading">{{box[1].title}}</h4>
180
- {% assign type = box[1].type %}
181
- {% if type == 'linkbox' %}
182
- {% assign links = box[1].links %}
183
- {% for link in links %}
72
+
73
+ {% for item in box[1] %}
74
+ {% assign key = item[0] %}
75
+ {% assign value = item[1] %}
76
+ {% if key == 'enabled' %} {% assign enabled = value %} {% endif %}
77
+ {% if key == 'type' %} {% assign type = value %} {% endif %}
78
+ {% if key == 'title' %} {% assign title = value %} {% endif %}
79
+ {% if key == 'type' %} {% assign type = value %} {% endif %}
80
+ {% if key == 'links' %} {% assign links = value %} {% endif %}
81
+ {% endfor %}
82
+
83
+ {% if enabled %}
84
+ {% case type %}
85
+
86
+ {% comment %} Collect USER info
87
+ ---------------------------------------------------------------------- {% endcomment %}
88
+ {% when 'user_info' %}
89
+ <!-- [INFO ] [j1.modules.navigator.sidebar.proc ] [USER info enabled] -->
90
+ <!-- [INFO ] [j1.modules.navigator.sidebar.proc ] [Write widged placeholder: USER info] -->
91
+ <div id="user-info" class="widget">
92
+ <h4 class="heading">{{title}}</h4>
93
+ <ul id="display_user_details" class="link">
94
+ {% for link in links %}
95
+
96
+ {% if link.icon == null %}
97
+ {% assign icon = '' %}
98
+ {% else %}
99
+ {% capture icon %}<i class="{{icon_family}} {{icon_family}}-{{link.icon}} {{icon_size}} mr-2" {{icon_color}}></i>{% endcapture %}
100
+ {% endif %}
101
+
102
+ {% if link.target == null %}
103
+ {% assign target = '' %}
104
+ {% else %}
105
+ {% capture target %}target="{{link.target}}"{% endcapture %}
106
+ {% endif %}
107
+
108
+ {% if link.value == null %}
109
+ {% assign link_text = link.title %}
110
+ {% else %}
111
+ {% if link.value contains '??' %}
112
+ {% capture macro_name %}{{link.value|replace: '?',''|downcase}}{% endcapture %}
113
+ {% capture macro_id %}id="macro-{{macro_name}}"{% endcapture %}
114
+ {% else %}
115
+ {% assign macro_id = '' %}
116
+ {% endif %}
117
+ {% capture link_text %}{{link.title}}: {{link.value}}{% endcapture %}
118
+ {% endif %}
119
+
120
+ <li><a {{macro_id}} href="{{link.href|strip}}" {{target}}>{{icon}} {{link_text}}</a></li>
121
+
122
+ {% endfor %}
123
+ </ul>
124
+ </div>
125
+
126
+ {% comment %} END Collect USER info
127
+ ---------------------------------------------------------------------- {% endcomment %}
128
+
129
+ {% comment %} Reset element variables
130
+ ---------------------------------------------------------------------- {% endcomment %}
131
+ {% assign enabled = nil %}
132
+ {% assign type = nil %}
133
+ {% assign title = nil %}
134
+ {% assign type = nil %}
135
+ {% assign links = nil %}
136
+
137
+ {% comment %} Collect THEME info
138
+ ---------------------------------------------------------------------- {% endcomment %}
139
+ {% when 'theme_info' %}
140
+ <!-- [INFO ] [j1.modules.navigator.sidebar.proc ] [THEME info detected] -->
141
+ <!-- [INFO ] [j1.modules.navigator.sidebar.proc ] [Write widged placeholder: USER info] -->
142
+ <div id="theme-info" class="widget">
143
+ <h4 class="heading">{{title}}</h4>
144
+ <ul class="link">
145
+ {% for link in links %}
146
+
147
+ {% if link.icon == null %}
148
+ {% assign icon = '' %}
149
+ {% else %}
150
+ {% capture icon %}<i class="{{icon_family}} {{icon_family}}-{{link.icon}} {{icon_size}} mr-2" {{icon_color}}></i>{% endcapture %}
151
+ {% endif %}
152
+
153
+ {% if link.target == null %}
154
+ {% assign target = '' %}
155
+ {% else %}
156
+ {% capture target %}target="{{link.target}}"{% endcapture %}
157
+ {% endif %}
158
+
159
+ {% if link.value == null %}
160
+ {% assign link_text = link.title %}
161
+ {% else %}
162
+ {% if link.value contains '??' %}
163
+ {% capture macro_name %}{{link.value|replace: '?',''|downcase}}{% endcapture %}
164
+ {% capture macro_id %}id="macro-{{macro_name}}"{% endcapture %}
165
+ {% else %}
166
+ {% assign macro_id = '' %}
167
+ {% endif %}
168
+ {% capture link_text %}{{link.title}}: {{link.value}}{% endcapture %}
169
+ {% endif %}
170
+
171
+ <li><a {{macro_id}} href="{{link.href|strip}}" {{target}}>{{icon}} {{link_text}}</a></li>
172
+
173
+ {% endfor %}
174
+ </ul>
175
+ </div>
176
+ <!-- [INFO ] [j1.modules.navigator.sidebar.proc ] [End processing: THEME info] -->
177
+
178
+ {% comment %} END Collect THEME info
179
+ ---------------------------------------------------------------------- {% endcomment %}
180
+
181
+ {% comment %} Reset element variables
182
+ ---------------------------------------------------------------------- {% endcomment %}
183
+ {% assign enabled = nil %}
184
+ {% assign type = nil %}
185
+ {% assign title = nil %}
186
+ {% assign type = nil %}
187
+ {% assign links = nil %}
188
+
189
+ {% comment %} Collect SITE info
190
+ ---------------------------------------------------------------------- {% endcomment %}
191
+ {% when 'site_info' %}
192
+ <!-- [INFO ] [j1.modules.navigator.sidebar.proc] [Start processing SITE info] -->
193
+
194
+ <div id="site-info" class="widget">
195
+ <h4 class="heading">{{title}}</h4>
184
196
  <ul class="link">
185
- <li><a href="{{ link[1] }}">{{ link[0] }}</a></li>
197
+ {% for link in links %}
198
+ {% if link.icon == null %}
199
+ {% assign icon = "" %}
200
+ {% else %}
201
+ {% capture icon %}<i class="{{icon_family}} {{icon_family}}-{{link.icon}} {{icon_size}} mr-2" {{icon_color}}></i>{% endcapture %}
202
+ {% endif %}
203
+ {% if link.target == null %}
204
+ {% assign target = "" %}
205
+ {% else %}
206
+ {% capture target %}target="{{link.target}}"{% endcapture %}
207
+ {% endif %}
208
+ {% if link.value == null %}
209
+ {% assign link_text = link.title %}
210
+ {% else %}
211
+ {% capture link_text %}"{{link.title}}: {{link.title}}"{% endcapture %}
212
+ {% endif %}
213
+
214
+ <li><a href="{{link.href|strip}}" {{target}}>{{icon}}{{link_text}}</a></li>
215
+
216
+ {% endfor %}
186
217
  </ul>
187
- {% endfor %}
188
- {% endif %}
189
- </div>
218
+ </div>
219
+
220
+ {% comment %} END Collect SITE info
221
+ ---------------------------------------------------------------------- {% endcomment %}
222
+
223
+ {% comment %} Reset element variables
224
+ ---------------------------------------------------------------------- {% endcomment %}
225
+ {% assign enabled = nil %}
226
+ {% assign type = nil %}
227
+ {% assign title = nil %}
228
+ {% assign type = nil %}
229
+ {% assign links = nil %}
230
+
231
+ {% endcase %}
190
232
  {% endif %}
191
- {% endfor %}
233
+
234
+ {% endfor %}
192
235
  {% endfor %}
193
- <!-- [INFO ] [j1.modules.navigator.sidebar.proc ] [end processing: sidebar boxes] -->
236
+ <!-- [INFO ] [j1.modules.navigator.sidebar.proc ] [End processing sidebar boxes] -->
194
237
 
195
238
  </div>
196
- <!-- [INFO ] [j1.modules.navigator.sidebar.proc ] [end processing: sidebar] -->
239
+ <!-- [INFO ] [j1.modules.navigator.sidebar.proc ] [End processing: sidebar] -->
240
+
241
+
242
+
243
+
data/lib/j1/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module J1
2
- VERSION = '2018.4.15'
2
+ VERSION = '2018.4.16'
3
3
  end
data/lib/j1_app.rb CHANGED
@@ -18,10 +18,12 @@ require 'active_support/core_ext'
18
18
  require 'dotenv'
19
19
  require 'json'
20
20
  require 'safe_yaml'
21
+ require 'rest-client'
21
22
 
22
23
  require 'puma'
23
24
 
24
25
  require 'rack'
26
+ require 'rack-livereload'
25
27
  require 'omniauth'
26
28
  require 'omniauth-oauth2'
27
29
  require 'sinatra'
@@ -61,8 +63,9 @@ Dotenv.load
61
63
  module J1App
62
64
  def self.site
63
65
  Rack::Builder.new do
66
+ use Rack::LiveReload #, force_swf: true , :source => :livereload Middleware. Support Livereload
64
67
  use Rack::ShowExceptions # Middleware. Generate web-based error pages (for Rack)
65
- use J1App::AuthManager # Middleware. Support authentication methods using OmniAuth
68
+ use J1App::AuthManager # Middleware. Support authentication methods using OmniAuth
66
69
  run J1App::SiteManager # Run J1App Manager to manage the (static) site as an (Rack-based) Web Application:
67
70
  end
68
71
  end
@@ -0,0 +1,939 @@
1
+ # frozen_string_literal: true
2
+
3
+ # ------------------------------------------------------------------------------
4
+ # ~/lib/j1_auth_manager/auth_manager/.rb
5
+ #
6
+ # Provides authentication services based on Warden|OmniAuth
7
+ #
8
+ # Product/Info:
9
+ # https://jekyll-one.com
10
+ #
11
+ # Copyright (C) 2019 Juergen Adams
12
+ #
13
+ # J1 Template is licensed under the MIT License.
14
+ # See: https://github.com/jekyll-one/j1_template_mde/blob/master/LICENSE
15
+ #
16
+ # ------------------------------------------------------------------------------
17
+ # NOTES
18
+ #
19
+ # ------------------------------------------------------------------------------
20
+ module J1App
21
+ class AuthManager < Sinatra::Base
22
+
23
+ include J1App::Helpers
24
+ include J1App::GithubHelpers
25
+
26
+ # ==========================================================================
27
+ # Sinatra Framework settings
28
+ # ==========================================================================
29
+
30
+ # NOTE: https://stackoverflow.com/questions/7847536/sinatra-in-facebook-iframe
31
+ #
32
+ #set :protection, :except => :frame_options
33
+
34
+ # Check: http://sinatrarb.com/intro.html
35
+ #
36
+ #set :static_cache_control, [:public, :max_age => 10]
37
+
38
+
39
+ # ==========================================================================
40
+ # Base App and Warden Framework settings
41
+ # ==========================================================================
42
+
43
+ j1_web_session = {
44
+ :authenticated => 'false',
45
+ :requested_page => '/',
46
+ :user_name => 'unknown',
47
+ :users_allowed => 'unknown',
48
+ :user_id => 'unknown',
49
+ :provider => 'unknown',
50
+ :provider_url => '/',
51
+ :payment_info => 'unknown',
52
+ :permissions => 'unknown',
53
+ :writer => 'middleware'
54
+ }
55
+
56
+ # Enable SSL for the rack session if configured
57
+ # --------------------------------------------------------------------------
58
+ configure :production do
59
+ require 'rack-ssl-enforcer'
60
+ use Rack::SslEnforcer if J1App.ssl?
61
+ end
62
+
63
+ # Set the session cookie used by Rack to track all relevant data
64
+ # for the authentication service
65
+ # --------------------------------------------------------------------------
66
+ use Rack::Session::Cookie,
67
+ http_only: true,
68
+ key: 'j1.app.session',
69
+ secret: ENV['J1_SESSION_SECRET'] || SecureRandom.hex
70
+
71
+
72
+ # ==========================================================================
73
+ # Warden Framework initialisation
74
+ # ==========================================================================
75
+
76
+ # Define what (user) data should be put (serialized) into the session
77
+ # on requests and responses from Rack environment into the warden
78
+ # environment (env['warden']).
79
+ # --------------------------------------------------------------------------
80
+ Warden::Manager.serialize_into_session do |user|
81
+ user
82
+ end
83
+ Warden::Manager.serialize_from_session do |user|
84
+ user
85
+ end
86
+
87
+
88
+ # ==========================================================================
89
+ # OmniAuth|Warden Framework initialisation
90
+ # ==========================================================================
91
+
92
+ # Set the 'default' authentication strategy and exception handler
93
+ # (for warden) if the user was not explicitly signed in (signin dialog).
94
+ # If 'signin' fails, the default exception 'signin_failure' is thrown
95
+ # (used for all OmniAuth strategies registered).
96
+ # --------------------------------------------------------------------------
97
+ signin_failure = ->(_e) { Rack::Response.new("Can't login", 401).finish }
98
+ use Warden::Manager do |config|
99
+ # OmniAuth strategies are name-spaced by 'omni' (see: warden_omniauth.rb)
100
+ # ------------------------------------------------------------------------
101
+ config.default_strategies :"omni_#{J1App.default_provider}"
102
+ config.failure_app = signin_failure
103
+ end
104
+
105
+ use OmniAuth::Builder do |config|
106
+ # Workaround to rescue OmniAuth::Strategies::OAuth2::CallbackError?
107
+ # for chromium based browsers (e.g. google-chrome)
108
+ # ------------------------------------------------------------------------
109
+ config.on_failure do
110
+ new_path = '/redirect_requested_page'
111
+ Rack::Response.new(['302 Moved'], 302, 'Location' => new_path).finish
112
+ end
113
+
114
+ # Detect and set supported authentication strategies for OmniAuth
115
+ # ------------------------------------------------------------------------
116
+
117
+ # Additional (strategy) option skip_extra, default: true
118
+ #
119
+ # If true, skips the collection of raw data (extra) to NOT blow
120
+ # up the session cookie (as it is limited to 4K)
121
+ skip_extra = true
122
+
123
+ if J1App.active_providers.include? 'patreon'
124
+ scope = J1App.auth_config['providers']['patreon']['scope'].join(',')
125
+ data_collection = J1App.auth_config['providers']['patreon']['data_fields'].join(',')
126
+ skip_extra = false if data_collection =~ /raw/i
127
+ provider :patreon,
128
+ ENV['PATREON_CLIENT_ID'],
129
+ ENV['PATREON_CLIENT_SECRET'],
130
+ scope: "#{scope}",
131
+ skip_extra: skip_extra
132
+ end
133
+ if J1App.active_providers.include? 'disqus'
134
+ scope = J1App.auth_config['providers']['disqus']['scope'].join(',')
135
+ data_collection = J1App.auth_config['providers']['disqus']['data_fields'].join(',')
136
+ skip_extra = false if data_collection =~ /raw/i
137
+ provider :disqus,
138
+ ENV['DISQUS_CLIENT_ID'],
139
+ ENV['DISQUS_CLIENT_SECRET'],
140
+ scope: "#{scope}",
141
+ skip_extra: skip_extra
142
+ end
143
+ if J1App.active_providers.include? 'facebook'
144
+ scope = J1App.auth_config['providers']['facebook']['scope'].join(',')
145
+ data_collection = J1App.auth_config['providers']['facebook']['data_fields'].join(',')
146
+ skip_extra = false if data_collection =~ /raw/i
147
+ provider :facebook,
148
+ ENV['FACEBOOK_CLIENT_ID'],
149
+ ENV['FACEBOOK_CLIENT_SECRET'],
150
+ scope: "#{scope}",
151
+ skip_extra: skip_extra
152
+ end
153
+ if J1App.active_providers.include? 'github'
154
+ scope = J1App.auth_config['providers']['github']['scope'].join(',')
155
+ data_collection = J1App.auth_config['providers']['github']['data_fields'].join(',')
156
+ skip_extra = false if data_collection =~ /raw/i
157
+ provider :github,
158
+ ENV['GITHUB_CLIENT_ID'],
159
+ ENV['GITHUB_CLIENT_SECRET'],
160
+ scope: "#{scope}",
161
+ skip_extra: skip_extra
162
+ end
163
+ if J1App.active_providers.include? 'twitter'
164
+ scope = J1App.auth_config['providers']['twitter']['scope'].join(',')
165
+ data_collection = J1App.auth_config['providers']['twitter']['data_fields'].join(',')
166
+ skip_extra = false if data_collection =~ /raw/i
167
+ provider :twitter,
168
+ ENV['TWITTER_CLIENT_ID'],
169
+ ENV['TWITTER_CLIENT_SECRET'],
170
+ scope: "#{scope}",
171
+ skip_extra: skip_extra
172
+ end
173
+ end
174
+
175
+ # Set the (internal) endpoint if a user is successfully authenticated
176
+ # --------------------------------------------------------------------------
177
+ use J1WardenOmniAuth do |config|
178
+ config.redirect_after_callback = '/redirect_after_callback'
179
+ end
180
+
181
+ # Add the internal logger from Rack to the middleware's of the stack
182
+ # --------------------------------------------------------------------------
183
+ use Rack::Logger
184
+
185
+ # Load user profiles, permissions, conditions and strategies
186
+ # --------------------------------------------------------------------------
187
+
188
+ providers = J1App.auth_config['providers']
189
+ permissions = J1App.permissions
190
+
191
+
192
+ # ==========================================================================
193
+ # Sinatra (before) FILTER to preprocess all page requests
194
+ # ==========================================================================
195
+
196
+ # Prepare root (index) page for app detection
197
+ #
198
+ before '/' do
199
+ log_info! "RootPage", "PrepareCookie", 'j1.web.session'
200
+ #logger.info "ROOT PAGE: Prepare J1 web session data"
201
+
202
+ # read existing/current cookie 'j1.web.session' to update all data
203
+ # of j1_web_session (hash) otherwise set initial data
204
+ # ------------------------------------------------------------------------
205
+ unless env['HTTP_COOKIE'] == nil
206
+ if env['HTTP_COOKIE'].include? 'j1.web.session'
207
+ session_encoded = request.cookies['j1.web.session']
208
+ session_decoded = Base64.decode64(session_encoded)
209
+ j1_web_session = JSON.parse(session_decoded)
210
+ end
211
+ else
212
+ requested_page = env['REQUEST_URI']
213
+ j1_web_session['requested_page'] = "#{env['REQUEST_URI']}"
214
+ end
215
+
216
+ # Create|Initialize the J1 web session cookie
217
+ # ------------------------------------------------------------------------
218
+ if warden.authenticated?
219
+ log_info! "RootPage", 'UpdateCookie', 'Set current user data'
220
+
221
+ user = warden.user
222
+ log_info! "RootPage", 'AuthCheck', 'User detected as signed in', "#{user[:provider]}"
223
+ j1_web_session['authenticated'] = 'true'
224
+ j1_web_session['requested_page'] = '/'
225
+ j1_web_session['users_allowed'] = providers["#{user[:provider]}"]['users']
226
+ j1_web_session['user_name'] = user[:info]['nickname']
227
+ j1_web_session['user_id'] = user[:uid]
228
+ j1_web_session['provider'] = user[:provider]
229
+ j1_web_session['provider_url'] = providers["#{user[:provider]}"]['home_url']
230
+ j1_web_session['permissions'] = providers["#{user[:provider]}"]['permissions']
231
+ j1_web_session['payment_info'] = user[:info]['payment_info']['attributes'] unless user[:info]['payment_info'].nil?
232
+ else
233
+ log_info! "RootPage", 'AuthCheck', 'User detected', 'signed out'
234
+ j1_web_session['authenticated'] = 'false'
235
+ j1_web_session['requested_page'] = '/'
236
+ j1_web_session['users_allowed'] = 'all'
237
+ j1_web_session['user_name'] = 'unknown'
238
+ j1_web_session['user_id'] = 'unknown'
239
+ j1_web_session['payment_info'] = 'unknown'
240
+ j1_web_session['provider'] = 'unknown'
241
+ j1_web_session['provider_url'] = 'unknown'
242
+ j1_web_session['permissions'] = 'unknown'
243
+ end
244
+ j1_web_session['writer'] = 'middleware'
245
+
246
+ session_json = j1_web_session.to_json
247
+ log_info! "RootPage", 'WriteCookie', 'j1.web.session' # "#{session_json}"
248
+
249
+ session_encoded = Base64.encode64(session_json)
250
+ response.set_cookie(
251
+ 'j1.web.session',
252
+ domain: false,
253
+ value: session_encoded.to_s,
254
+ path: '/'
255
+ )
256
+ end
257
+
258
+ # Check auth status for content of type "private" or "premium"
259
+ # --------------------------------------------------------------------------
260
+ #before '/*' do
261
+ #before /\/\w+\/(public|private|premium)/ do
262
+ before '/(pages|posts)/*' do
263
+
264
+ # read existing/current cookie 'j1.web.session'
265
+ # to update all data of j1_web_session (hash)
266
+ # if request.warden.user.respond_to?(:info)
267
+ # ------------------------------------------------------------------------
268
+ if env['HTTP_COOKIE'].include? 'j1.web.session'
269
+ session_encoded = request.cookies['j1.web.session']
270
+ session_decoded = Base64.decode64(session_encoded)
271
+ j1_web_session = JSON.parse(session_decoded)
272
+
273
+ log_info! 'Authorisation', 'ReadCookie', 'j1.web.session' # "#{session_decoded}"
274
+ else
275
+ requested_page = env['REQUEST_URI']
276
+ j1_web_session['requested_page'] = "#{env['REQUEST_URI']}"
277
+ end
278
+
279
+ # Create|Initialize the J1 web session cookie
280
+ # ------------------------------------------------------------------------
281
+ if warden.authenticated?
282
+ log_info! 'Authorisation', 'UpdateCookie', 'Set current user data'
283
+
284
+ user = warden.user
285
+ j1_web_session['authenticated'] = 'true'
286
+ j1_web_session['user_name'] = user[:info]['nickname']
287
+ j1_web_session['user_id'] = user[:uid]
288
+ j1_web_session['provider'] = user[:provider]
289
+ j1_web_session['provider_url'] = providers["#{user[:provider]}"]['home_url']
290
+ j1_web_session['users_allowed'] = providers["#{user[:provider]}"]['users']#
291
+ j1_web_session['permissions'] = providers["#{user[:provider]}"]['permissions']
292
+ j1_web_session['payment_info'] = user[:info]['payment_info']['attributes'] unless user[:info]['payment_info'].nil?
293
+ j1_web_session['writer'] = 'middleware'
294
+
295
+ session_json = j1_web_session.to_json
296
+ log_info! 'Authorisation', 'WriteCookie', 'j1.web.session' # "#{session_json}"
297
+
298
+ session_encoded = Base64.encode64(session_json)
299
+ response.set_cookie(
300
+ 'j1.web.session',
301
+ domain: false,
302
+ value: session_encoded.to_s,
303
+ path: '/'
304
+ )
305
+ end
306
+
307
+ # User state|content detection for implicit authentication
308
+ # ------------------------------------------------------------------------
309
+ log_info! 'Authorisation', 'CheckConfig', 'Authentication enabled', "false" if authentication_enabled? == false
310
+ log_info! 'Authorisation', 'CheckConfig', 'Pass for all pages' if authentication_enabled? == false
311
+ pass if authentication_enabled? == false
312
+ log_info! 'Authorisation', 'CheckConfig', 'Authentication enabled', "true"
313
+ log_info! 'Authorisation', 'DetectContent', 'Check for public content' if public_content?
314
+ log_info! 'Authorisation', 'DetectContent', 'Pass all public content' if public_content?
315
+ pass if public_content?
316
+ log_info! 'Authorisation', 'DetectContent', 'Check for protected content'
317
+
318
+ requested_page = env['REQUEST_URI']
319
+
320
+ requested_page.scan(/(private|premium)/) do |match|
321
+
322
+ category = match[0]
323
+ log_info! 'Authorisation', 'DetectContent', 'Content detected', "#{category}"
324
+
325
+ if warden.authenticated?
326
+ log_info! 'Authorisation', 'UpdateCookie', 'Set current user data'
327
+
328
+ user_name = user[:info]['nickname']
329
+ log_info! 'Authorisation', 'AuthCheck', 'User detected', "#{user_name}"
330
+
331
+ current_provider = warden.user[:provider]
332
+
333
+ # provider_strategy = strategies["#{default_provider}"]
334
+ strategy = providers["#{current_provider}"]['strategy']
335
+ provider_strategy = :"#{strategy}"
336
+
337
+ j1_web_session['user_name'] = user_name
338
+ j1_web_session['provider_url'] = providers["#{current_provider}"]['home_url']
339
+ j1_web_session['users_allowed'] = providers["#{current_provider}"]['users']
340
+ j1_web_session['permissions'] = providers["#{user[:provider]}"]['permissions']
341
+ j1_web_session['requested_page'] = requested_page
342
+
343
+ if permissions[:"#{category}"].include? current_provider
344
+ log_info! 'Authorisation', 'ContentCheck', 'Provider detected', "#{current_provider}"
345
+ log_info! 'Authorisation', 'ContentCheck', 'Category supported', "yes - #{category}"
346
+ # Check permissions
347
+ #
348
+ log_info! 'Authorisation', 'ConditionCheck', 'Check permissions for provider', "#{current_provider}"
349
+ conditions = J1App.conditions current_provider
350
+ if conditions["#{category}"]
351
+ log_info! 'Authorisation', 'ConditionCheck', 'Conditions detected for', "#{category}"
352
+ conditions["#{category}"].each do |k, v|
353
+ case k
354
+ when 'enabled'
355
+ log_info! 'Authorisation', 'ConditionCheck', "#{k}", "#{v}"
356
+ when 'users'
357
+ log_info! 'Authorisation', 'ConditionCheck', 'users'
358
+ v.each do |k, v|
359
+ log_info! 'Authorisation', 'ConditionCheck', "users - #{k}", "#{v}"
360
+ end
361
+ when 'payment'
362
+ log_info! 'Authorisation', 'ConditionCheck', 'payment'
363
+ v.each do |k, v|
364
+ case k
365
+ when 'tiers'
366
+ log_info! 'Authorisation', 'ConditionCheck', "payment - #{k}", "#{v}"
367
+ when 'tier'
368
+ v.each do |k, v|
369
+ log_info! 'Authorisation', 'ConditionCheck', 'payment - tiers - tier : ' "#{k}", "#{v}"
370
+ end
371
+ end
372
+ end
373
+ end
374
+ end
375
+ end
376
+ else
377
+ provider = permissions[:"#{category}"][0]
378
+ log_info! 'Authorisation', 'ContentCheck', 'Provider detected', "#{current_provider}"
379
+ log_info! 'Authorisation', 'ContentCheck', 'Category supported', "no - #{category}"
380
+ log_info! 'Authorisation', 'SignIn', 'Provider', "#{provider}"
381
+ warden.logout
382
+ session.clear
383
+
384
+ session_json = j1_web_session.to_json
385
+ log_info! 'Authorisation', 'WriteCookie', 'j1.web.session' # "#{session_json}"
386
+
387
+ session_encoded = Base64.encode64(session_json)
388
+ response.set_cookie(
389
+ 'j1.web.session',
390
+ domain: false,
391
+ value: session_encoded.to_s,
392
+ path: '/'
393
+ )
394
+
395
+ log_info! 'Authorisation', 'AuthManager', 'Request for authentication'
396
+
397
+ allowed_users = providers["#{provider}"]['users'].join(',')
398
+ redirect "/access_protected_content?provider=#{provider}&category=#{category}&page=#{requested_page}&allowed_users=#{allowed_users}"
399
+ end
400
+ log_info! 'Authorisation', 'AuthCheck', 'Pass to requested page', "#{requested_page}"
401
+ pass
402
+ else
403
+ log_info! 'Authentication', 'AuthCheck', 'User detected', 'signed out'
404
+ default_provider = permissions[:"#{category}"][0]
405
+ log_info! 'Authentication', 'ContentCheck', 'Set default provider', "#{default_provider}"
406
+
407
+ # provider_strategy = strategies["#{default_provider}"]
408
+ strategy = providers["#{default_provider}"]['strategy']
409
+ provider_strategy = :"#{strategy}"
410
+
411
+ log_info! 'Authentication', 'SignIn', 'Default provider detected', "#{default_provider}"
412
+ log_info! 'Authentication', 'SignIn', 'Set authentication strategy', "#{provider_strategy}"
413
+
414
+ case provider_strategy
415
+
416
+ when :org
417
+ warden.authenticate!
418
+ github_organization_authenticate! ENV['GITHUB_ORG_NAME']
419
+ logger.info "Hi There, #{j1_web_session[:user_name]}! You have access to the #{params['id']} organization"
420
+
421
+ when :team
422
+ warden.authenticate!
423
+ github_team_authenticate! ENV['GITHUB_TEAM_ID']
424
+ logger.info "Hi There, #{j1_web_session[:user_name]}! You have access to the #{params['id']} team"
425
+
426
+ when :teams
427
+ warden.authenticate!
428
+ github_teams_authenticate! ENV['GITHUB_TEAM_IDS'].split(',')
429
+ logger.info "Hi There, #{j1_web_session[:user_name]}! You have access to the #{params['id']} team"
430
+
431
+ when :member
432
+ log_info! 'Authentication', 'SignIn', "Strategy detected", "member"
433
+
434
+ if env['HTTP_COOKIE'].include? 'j1.web.session'
435
+ session_encoded = request.cookies['j1.web.session']
436
+ session_decoded = Base64.decode64(session_encoded)
437
+ log_info! 'Authentication', 'ReadCookie', 'j1.web.session' # "#{session_decoded}"
438
+ j1_web_session = JSON.parse(session_decoded)
439
+ end
440
+
441
+ # Update cookie data
442
+ # ----------------------------------------------------------------------
443
+ log_info! 'Authentication', 'UpdateCookie', 'Set current user data'
444
+
445
+ j1_web_session['provider_url'] = providers["#{default_provider}"]['home_url']
446
+ j1_web_session['users_allowed'] = providers["#{default_provider}"]['users']
447
+ j1_web_session['permissions'] = providers["#{default_provider}"]['permissions']
448
+ j1_web_session['requested_page'] = env['REQUEST_URI']
449
+ j1_web_session['writer'] = 'middleware'
450
+
451
+ # write updated J1 session cookie
452
+ #
453
+ session_json = j1_web_session.to_json
454
+ session_encoded = Base64.encode64(session_json)
455
+ log_info! 'Authentication', 'WriteCookie', 'j1.web.session' # "#{session_json}"
456
+
457
+ response.set_cookie(
458
+ 'j1.web.session',
459
+ domain: false,
460
+ value: session_encoded.to_s,
461
+ path: '/'
462
+ )
463
+
464
+ allowed_users = providers["#{default_provider}"]['users'].join(',')
465
+ requested_page = env['REQUEST_URI']
466
+
467
+ log_info! 'Authorisation', 'AuthManager', 'Request for authentication'
468
+ redirect "/access_protected_content?provider=#{default_provider}&category=#{category}&page=#{requested_page}&allowed_users=#{allowed_users}"
469
+ else
470
+ raise J1App::ConfigError
471
+ end
472
+
473
+ end
474
+ end
475
+ end
476
+
477
+
478
+ # ==========================================================================
479
+ # APP|API ENDPOINTS (Sinatra HANDLERS)
480
+ # ==========================================================================
481
+
482
+ # Authentication ENDPOINT called from the web (auth client)
483
+ # --------------------------------------------------------------------------
484
+ get '/authentication' do
485
+ # collect (common) GET parameter|s
486
+ #
487
+ request = params.fetch('request')
488
+ provider = params.fetch('provider')
489
+
490
+ if request === 'signin'
491
+
492
+ log_info! 'Authentication', 'RestApi', 'Called for SignIn'
493
+
494
+ # collect (additional) GET parameter|s
495
+ # ----------------------------------------------------------------------
496
+ allowed_users = params.fetch('allowed_users')
497
+
498
+ j1_web_session['users_allowed'] = allowed_users
499
+ j1_web_session['writer'] = 'middleware'
500
+
501
+ # Write updated J1 session data to cookie
502
+ # --------------------------------------------------------------------
503
+ session_json = j1_web_session.to_json
504
+ log_info! 'Authentication', 'RestApi', 'Write J1 web session data to cookie' # #{session_json}"
505
+
506
+ session_encoded = Base64.encode64(session_json)
507
+ response.set_cookie(
508
+ 'j1.web.session',
509
+ domain: false,
510
+ value: session_encoded.to_s,
511
+ path: '/'
512
+ )
513
+
514
+ if warden.authenticated?
515
+ log_info! 'Authentication', 'RestApi', 'Already signed in', "#{warden.user[:info]['nickname']} "
516
+ else
517
+ log_info! 'Authentication', 'RestApi', 'Go for authentication', "#{provider}"
518
+ # Make (really) sure that old session is cleared before login
519
+ # --------------------------------------------------------------------
520
+ warden.logout
521
+ session.clear
522
+ warden.authenticate! :"omni_#{provider}"
523
+ end
524
+ log_info! 'Authentication', 'RestApi', 'Requested page', "#{j1_web_session['requested_page']}"
525
+ redirect j1_web_session['requested_page']
526
+ elsif request === 'signout'
527
+
528
+ log_info! 'Authentication', 'RestApi', 'Called for sign out'
529
+
530
+ # collect (additional) GET parameter|s
531
+ # ----------------------------------------------------------------------
532
+ provider_signout = params.fetch('provider_signout')
533
+
534
+ if warden.authenticated?
535
+ user = warden.user[:info]['nickname']
536
+ provider = warden.user[:provider]
537
+ provider_url = j1_web_session['provider_url']
538
+ warden.logout
539
+ session.clear
540
+
541
+ # Read current J1 web session cookie
542
+ # --------------------------------------------------------------------
543
+ if env['HTTP_COOKIE'].include? 'j1.web.session'
544
+ session_encoded = env['rack.request.cookie_hash']['j1.web.session']
545
+ session_decoded = Base64.decode64(session_encoded)
546
+ log_info! 'Authentication', 'RestApi', 'Read J1 web session data from cookie' # #{session_decoded}"
547
+ j1_web_session = JSON.parse(session_decoded)
548
+ else
549
+ j1_web_session['requested_page'] = env['REQUEST_URI']
550
+ end
551
+
552
+ # Update J1 web session data
553
+ # --------------------------------------------------------------------
554
+ j1_web_session['user_name'] = 'unknown'
555
+ j1_web_session['user_id'] = 'unknown'
556
+ j1_web_session['users_allowed'] = 'unknown'
557
+ j1_web_session['payment_info'] = 'unknown'
558
+ j1_web_session['provider'] = 'unknown'
559
+ j1_web_session['provider_url'] = 'unknown'
560
+ j1_web_session['permissions'] = 'unknown'
561
+ j1_web_session['authenticated'] = 'false'
562
+ j1_web_session['writer'] = 'middleware'
563
+
564
+ # Write updated J1 session data to cookie
565
+ # --------------------------------------------------------------------
566
+ session_json = j1_web_session.to_json
567
+ log_info! 'Authentication', 'RestApi', 'Write J1 web session data to cookie' # #{session_json}"
568
+
569
+ session_encoded = Base64.encode64(session_json)
570
+ response.set_cookie(
571
+ 'j1.web.session',
572
+ domain: false,
573
+ value: session_encoded.to_s,
574
+ path: '/'
575
+ )
576
+
577
+ if provider_signout === 'true'
578
+ log_info! 'Authentication', 'RestApi', 'Sign out user', "#{user}"
579
+ log_info! 'Authentication', 'RestApi', 'Sign out provider', "#{provider}"
580
+ log_info! 'Authentication', 'RestApi', 'Sign out from', "#{provider}"
581
+ log_info! 'Authentication', 'RestApi', 'Redirect to provider', "#{provider_url}"
582
+ redirect "#{provider_url}"
583
+ else
584
+ log_info! 'Authentication', 'RestApi', 'Sign out user', "#{user}"
585
+ log_info! 'Authentication', 'RestApi', 'Sign out provider', "#{provider}"
586
+ log_info! 'Authentication', 'RestApi', 'Sign out from', "session"
587
+ log_info! 'Authentication', 'RestApi', 'Redirect to page', "#{j1_web_session['requested_page']}"
588
+
589
+ # If signed out, redirect ONLY for PUBLIC pages
590
+ # ------------------------------------------------------------------
591
+ if redirect_whitelisted?j1_web_session['requested_page']
592
+ log_info! 'Authentication', 'RestApi', 'Redirect detetced as', "whitelisted"
593
+ log_info! 'Authentication', 'RestApi', 'Requested page', "#{j1_web_session['requested_page']}"
594
+ redirect j1_web_session['requested_page']
595
+ else
596
+ log_info! 'Authentication', 'RestApi', 'Redirect detetced as', "NOT whitelisted"
597
+ log_info! 'Authentication', 'RestApi', 'Redirect to', "/"
598
+ redirect '/'
599
+ end
600
+ end
601
+ else
602
+ # THIS condition should NEVER REACHED because NO logout dialog
603
+ # (modal) is provided by the auth client if a user isn't signed in.
604
+ # Kept this alternative for cases something went wrong.
605
+ # --------------------------------------------------------------------
606
+ log_info! 'Authentication', 'RestApi', 'DEAD PATH: Called for sign out', 'NOT signed in'
607
+
608
+ # Read current J1 session cookie
609
+ # --------------------------------------------------------------------
610
+ if env['HTTP_COOKIE'].include? 'j1.web.session'
611
+ session_encoded = env['rack.request.cookie_hash']['j1.web.session']
612
+ session_decoded = Base64.decode64(session_encoded)
613
+ j1_web_session = JSON.parse(session_decoded)
614
+
615
+ log_info! 'Authentication', 'RestApi', 'DEAD PATH: Read J1 web session data from cookie' # #{session_decoded}"
616
+ else
617
+ j1_web_session['requested_page'] = env['REQUEST_URI']
618
+ end
619
+
620
+ # Update J1 web session data
621
+ # --------------------------------------------------------------------
622
+ j1_web_session['user_name'] = 'unknown'
623
+ j1_web_session['user_id'] = 'unknown'
624
+ j1_web_session['users_allowed'] = 'unknown'
625
+ j1_web_session['payment_info'] = 'unknown'
626
+ j1_web_session['provider'] = 'unknown'
627
+ j1_web_session['provider_url'] = 'unknown'
628
+ j1_web_session['permissions'] = 'unknown'
629
+ j1_web_session['authenticated'] = 'false'
630
+ j1_web_session['writer'] = 'middleware'
631
+
632
+ # Write updated J1 session data to cookie
633
+ # --------------------------------------------------------------------
634
+ session_json = j1_web_session.to_json
635
+ log_info! 'Authentication', 'RestApi', 'DEAD PATH: Write J1 web session data to cookie' # #{session_json}"
636
+
637
+ session_encoded = Base64.encode64(session_json)
638
+ response.set_cookie(
639
+ 'j1.web.session',
640
+ domain: false,
641
+ value: session_encoded.to_s,
642
+ path: '/'
643
+ )
644
+
645
+ log_info! 'Authentication', 'RestApi', 'DEAD PATH: Redirect to requested page', "#{j1_web_session['requested_page']}"
646
+ redirect j1_web_session['requested_page']
647
+ end
648
+ else
649
+ raise J1App::ConfigError
650
+ end
651
+ end
652
+
653
+ # Post-processing ENDPOINT called after a user is authenticated
654
+ # --------------------------------------------------------------------------
655
+ get '/redirect_after_callback' do
656
+
657
+ reward = {
658
+ :id => 'unknown',
659
+ :name => 'unknown',
660
+ :link => 'javascript:void(0)'
661
+ }
662
+
663
+ campaign = {
664
+ :id => 'unknown',
665
+ :link => 'javascript:void(0)'
666
+ }
667
+
668
+ session_encoded = request.cookies['j1.web.session']
669
+ session_decoded = Base64.decode64(session_encoded)
670
+ j1_web_session = JSON.parse(session_decoded)
671
+
672
+ log_info! 'Authentication', 'Callback', 'Update web session data' # "#{j1_web_session}"
673
+
674
+ user = warden.user
675
+ user_json = user.to_json
676
+
677
+ if user[:provider] === 'disqus'
678
+ user[:info][:urls][:site] = "https://disqus.com"
679
+ user[:info][:urls][:blog] = user[:info]['urls']['profileUrl']
680
+ end
681
+
682
+ if user[:provider] === 'github'
683
+ user[:info][:urls][:site] = user[:info]['urls']['GitHub']
684
+ user[:info][:urls][:blog] = user[:info]['urls']['Blog']
685
+ end
686
+
687
+ if user[:provider] === 'patreon'
688
+ reward_url = user[:info]['payment_info']['relationships']['reward']['links']['related']
689
+ reward_json = RestClient.get "#{reward_url}", {:content_type => :json, :accept => :json}
690
+ reward_data = JSON.parse(reward_json)
691
+
692
+ user[:info][:urls][:site] = "https://patreon.com"
693
+ user[:info][:urls][:blog] = reward_data['included'][0]['attributes']['url']
694
+
695
+ reward[:id] = reward_data['data']['id']
696
+ reward[:name] = reward_data['data']['attributes']['title']
697
+ reward[:link] = "https://patreon.com" + reward_data['data']['attributes']['url']
698
+
699
+ campaign[:id] = reward_data['data']['relationships']['campaign']['data']['id']
700
+ campaign[:link] = reward_data['data']['relationships']['campaign']['links']['related']
701
+ end
702
+
703
+ user[:extra][:reward] = reward
704
+ user[:extra][:campaign] = campaign
705
+
706
+ if user.nil?
707
+ # Collection of session data failed (e.g cookie > 4K)
708
+ #
709
+ log_info! 'Authentication', 'Callback', 'Internal error', 'User authentication failed'
710
+
711
+ warden.logout
712
+ session.clear
713
+ redirect "/access_denied?provider=unknown&user=unknown&category=unknown"
714
+ else
715
+ log_info! 'Authentication', 'Callback', 'Set current user data'
716
+
717
+ j1_web_session['user_name'] = user[:info]['nickname']
718
+ j1_web_session['user_id'] = user[:uid]
719
+ j1_web_session['provider'] = user[:provider]
720
+ j1_web_session['permissions'] = providers["#{user[:provider]}"]['permissions']
721
+ j1_web_session['authenticated'] = 'true'
722
+ j1_web_session['payment_info'] = user[:info]['payment_info']['attributes'] unless user[:info]['payment_info'].nil?
723
+ j1_web_session['writer'] = 'middleware'
724
+
725
+ current_user = user[:info]['nickname'] = user[:info]['nickname']
726
+ current_provider = user[:provider]
727
+
728
+ j1_web_session['requested_page'].scan(/(private|premium)/) do |match|
729
+ category = match[0]
730
+ unless j1_web_session['users_allowed'].include? 'all'
731
+ unless j1_web_session['users_allowed'].include? "#{current_user}"
732
+ log_info! 'Authentication', 'Callback', 'User not allowed', "#{current_user}"
733
+ log_info! 'Authentication', 'Callback', 'Allowed users', "#{j1_web_session['users_allowed']}"
734
+ warden.logout
735
+ session.clear
736
+ log_info! 'Authentication', 'Callback', 'User signed out', "#{current_user}"
737
+ redirect "/access_denied?provider=#{current_provider}&user=#{current_user}&category=#{category}"
738
+ end
739
+ end
740
+ end
741
+
742
+ end
743
+
744
+ j1_web_session['provider'] = current_provider
745
+ j1_web_session['users_allowed'] = providers["#{current_provider}"]['users']
746
+
747
+ if j1_web_session['requested_page'] == '/'
748
+ category = 'any protected content'
749
+ unless j1_web_session['users_allowed'].include? 'all'
750
+ unless j1_web_session['users_allowed'].include? "#{current_user}"
751
+ log_info! 'Authentication', 'Callback', 'User not allowed', "#{current_user}"
752
+ log_info! 'Authentication', 'Callback', 'Allowed users', "#{j1_web_session['users_allowed']}"
753
+ warden.logout
754
+ session.clear
755
+ log_info! 'Authentication', 'Callback', 'User signed out', "#{current_user}"
756
+ redirect "/access_denied?provider=#{current_provider}&user=#{current_user}&category=#{category}"
757
+ end
758
+ end
759
+ end
760
+
761
+ # write updated J1 session data to cookie
762
+ #
763
+ session_json = j1_web_session.to_json
764
+ log_info! 'Authentication', 'Callback', 'Write J1 web session data to cookie' # "#{session_json}"
765
+
766
+ session_encoded = Base64.encode64(session_json)
767
+ response.set_cookie(
768
+ 'j1.web.session',
769
+ domain: false,
770
+ value: session_encoded.to_s,
771
+ path: '/'
772
+ )
773
+
774
+ # redirect to requested page
775
+ #
776
+ log_info! 'Authentication', 'Callback', 'Signed in at provider', "#{user[:provider]}"
777
+ log_info! 'Authentication', 'Callback', 'Signed in as user', "#{user[:info]['nickname']}"
778
+ log_info! 'Authentication', 'Callback', 'Requested page', "#{j1_web_session['requested_page']}"
779
+ redirect j1_web_session['requested_page']
780
+ end
781
+
782
+ get '/redirect_requested_page' do
783
+ log_info! 'Authentication', 'RedirectPage', 'Requested page', "#{j1_web_session['requested_page']}"
784
+ redirect j1_web_session['requested_page']
785
+ end
786
+
787
+ # Status|Info ENDPOINT called from the web to get current state on an user
788
+ # --------------------------------------------------------------------------
789
+ get '/status' do
790
+ log_info! 'Status', 'RestApi', 'Info request detected'
791
+ session_encoded = request.cookies['j1.web.session']
792
+ session_decoded = Base64.decode64(session_encoded)
793
+ j1_web_session = JSON.parse(session_decoded)
794
+
795
+ # if request.warden.user.respond_to?(:info)
796
+ #
797
+ if warden.authenticated?
798
+ # user_json = warden.user.to_json
799
+ user = warden.user[:info]['nickname']
800
+ user_id = warden.user[:uid]
801
+ user_info = warden.user[:info]
802
+ provider = warden.user[:provider]
803
+ provider_url = warden.user[:info][:urls][:site]
804
+ provider_permissions = j1_web_session['permissions']
805
+
806
+ if provider == 'patreon'
807
+ user_member = warden.user[:extra][:reward][:name]
808
+ user_member_url = warden.user[:extra][:reward][:link]
809
+ else
810
+ user_member = 'unknown'
811
+ user_member_url = 'javascript:void(0)'
812
+ end
813
+
814
+ log_info! 'Status', 'RestApi', 'User detected as signed in', "#{user}"
815
+ else
816
+ user = 'unknown'
817
+ log_info! 'Status', 'RestApi', 'User detected', 'signed out'
818
+ end
819
+
820
+ # if request.warden.authenticated?
821
+ #
822
+ if user != 'unknown'
823
+ log_info! 'Status', 'RestApi', 'Send data for', 'SIGNED_IN'
824
+ content_type 'application/json'
825
+ {
826
+ user: user,
827
+ user_id: user_id,
828
+ provider: provider,
829
+ provider_url: provider_url,
830
+ permissions: provider_permissions,
831
+ membership: user_member,
832
+ memberurl: user_member_url,
833
+ status: 'signed in'
834
+ }.to_json
835
+ else
836
+ log_info! 'Status', 'RestApi', 'Send data for', 'SIGNED_OUT'
837
+ content_type 'application/json'
838
+ {
839
+ user: 'unknown',
840
+ user_id: 'unknown',
841
+ provider: 'unknown',
842
+ provider_url: 'javascript:void(0)',
843
+ permissions: 'unknown',
844
+ membership: 'unknown',
845
+ memberurl: 'javascript:void(0)',
846
+ status: 'signed out'
847
+ }.to_json
848
+ end
849
+ end
850
+
851
+ # access_protected_content ENDPOINT called from the app (auth manager)
852
+ # --------------------------------------------------------------------------
853
+ get '/access_denied' do
854
+
855
+ provider = params.fetch('provider')
856
+ category = params.fetch('category')
857
+ user = params.fetch('user')
858
+
859
+ session_encoded = request.cookies['j1.web.session']
860
+ session_decoded = Base64.decode64(session_encoded)
861
+ j1_web_session = JSON.parse(session_decoded)
862
+
863
+ # Update J1 web session data
864
+ # --------------------------------------------------------------------
865
+ j1_web_session['user_name'] = 'unknown'
866
+ j1_web_session['user_id'] = 'unknown'
867
+ j1_web_session['users_allowed'] = 'unknown'
868
+ j1_web_session['payment_info'] = 'unknown'
869
+ j1_web_session['provider'] = 'unknown'
870
+ j1_web_session['provider_url'] = 'unknown'
871
+ j1_web_session['permissions'] = 'unknown'
872
+ j1_web_session['authenticated'] = 'false'
873
+ j1_web_session['writer'] = 'middleware'
874
+
875
+ # write updated J1 session data to cookie
876
+ #
877
+
878
+ log_info! "AccessControl", 'RestApi', 'Exception', 'Access Denied'
879
+
880
+ session_json = j1_web_session.to_json
881
+ log_info! "AccessControl", 'RestApi', 'Write J1 web session data to cookie' # "#{session_json}"
882
+
883
+ session_encoded = Base64.encode64(session_json)
884
+ response.set_cookie(
885
+ 'j1.web.session',
886
+ domain: false,
887
+ value: session_encoded.to_s,
888
+ path: '/'
889
+ )
890
+
891
+ route = '/'
892
+
893
+ @route = route
894
+ @provider = provider
895
+ @modal = "centralModalInfo"
896
+ @info_type = "danger"
897
+ @modal_icon = "account-off"
898
+ @modal_ok_text = "Ok, understood"
899
+ @modal_title = "Authentication Manager"
900
+ @modal_description = "<h4>Access denied</h4></br></br> User <b>#{user}</b> from provider <b>#{provider}</b> is not allowed to access <b>#{category}</b> pages."
901
+
902
+ erb :auth_manager_ui
903
+ end
904
+
905
+ # access_protected_content ENDPOINT called from the app (auth manager)
906
+ # --------------------------------------------------------------------------
907
+ get '/access_protected_content' do
908
+
909
+ provider = params.fetch('provider')
910
+ allowed_users = params.fetch('allowed_users')
911
+ page = params.fetch('page')
912
+ category = params.fetch('category')
913
+
914
+ if warden.authenticated?
915
+ route = page
916
+ else
917
+ route = "/authentication?request=signin&provider=#{provider}&allowed_users=#{allowed_users}"
918
+ end
919
+
920
+ @provider = provider
921
+ @route = route
922
+ @modal = "signInProtectedContent"
923
+ @modal_icon = "login"
924
+ @modal_agreed_text = "Yes, please"
925
+ @modal_disagreed_text = "No, thanks"
926
+ @modal_title = "Authentication Manager"
927
+ @modal_image = "/assets/images/master_header/admin-dashboard-bootstrap-1280x600.png"
928
+ @modal_description = "The page <b>#{page}</b> you requested belongs to <b>#{category}</b> content. You'll be redirected to authenticate with the provider <b>#{provider}</b>. If signed in successfully, you get access to all <b>#{category} pages</b>."
929
+
930
+ erb :auth_manager_ui
931
+ end
932
+
933
+ get '/iframe' do
934
+ @website_url = "https://jekyll-one.github.io/"
935
+ erb :iframe
936
+ end
937
+
938
+ end
939
+ end