pseudo_kiosk 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: d55fa93717efba52a0ed428d4fc4ac23f25321792f7ab517fa5f25c6e516be3c
4
+ data.tar.gz: 36cad7483842d86cb7a394d06ff291d1ce96aa042bff143867721735fb1a1705
5
+ SHA512:
6
+ metadata.gz: 4a9bb2ea15dee2086fe4f73e0df30e5ed1b912f8782ea870f18c60c83501c59d7e8d85d1c4215c76d31af6755aedfdea51bdae9dc086db4744da950d649773b2
7
+ data.tar.gz: 6f610505ff484a4f85aaae880eb0064767dceedad968e48877a14510b143352b3b34c29a136f0fb5566d120661788859875bac6264a3abe640aeec960612713a
@@ -0,0 +1,20 @@
1
+ Copyright 2019
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,94 @@
1
+ # PseudoKiosk
2
+
3
+ ![Build Status](https://travis-ci.org/jonmchan/pseudo_kiosk.svg?branch=master)
4
+
5
+ PseudoKiosk is a play on words on the unix sudo command and the idea to provide a fake kiosk terminal. Instead of granting elevated privileges, PseudoKiosk gives the ability to limit access to the application during workflows which involve physically passing a device with elevated permissions to an unknown or untrusted user. PseudoKiosk provides the ability to lock down a rails application to only a specified whitelist of endpoints during a session. The kiosk can be quickly and easily unlocked by passing a kiosk passcode.
6
+
7
+ The motivating user scenario for this is a mobile, tablet, or kiosk device where data input must be received from an untrusted user while the device is mainly used by a privileged user (such as a cashier in a POS system). With PseudoKiosk, the device can be safely passed to the end customer to input his/her own information without fear of accidently or malicously utilizing the main user's elevated privileges.
8
+
9
+ After the form has been successfully submitted, a simple friendly unlock screen is provided for the privileged user to quickly unlock the kiosk and continue the workflow.
10
+
11
+ ## Demo
12
+
13
+ ![](doc/pseudo_kiosk_demo.gif)
14
+
15
+ You can also clone this repository and run the test application.
16
+
17
+ ```
18
+ git clone https://github.com/jonmchan/pseudo_kiosk.git
19
+ cd pseudo_kiosk
20
+ bundle install
21
+ bundle exec rails s
22
+ ```
23
+
24
+ Open http://localhost:3000 and you should see the same demo above. Passcode is `abc`.
25
+
26
+
27
+ ## Installation
28
+ Add this line to your application's Gemfile:
29
+
30
+ ```ruby
31
+ gem 'pseudo_kiosk'
32
+ ```
33
+
34
+ And then execute:
35
+ ```bash
36
+ $ bundle
37
+ ```
38
+
39
+ Or install it yourself as:
40
+ ```bash
41
+ $ gem install pseudo_kiosk
42
+ ```
43
+
44
+ ## Usage
45
+
46
+ Add the PseudoKiosk::Engine to your `config/routes.rb`:
47
+
48
+ ```
49
+ mount PseudoKiosk::Engine => "/pseudo_kiosk"
50
+ ```
51
+
52
+ Add the before_action script to check all requests if it is in protected or not by putting it in your `app/controller/application_controller.rb` file:
53
+
54
+ ```
55
+ before_action :secure_pseudo_kiosk
56
+ ```
57
+
58
+ Create an initializer to configure pseudo_kiosk in `config/initializers/pseudo_kiosk.rb`:
59
+
60
+ The unlock mechanism can be a simple unlock string such as:
61
+ ```
62
+ PseudoKiosk::Config.configure do |config|
63
+ config.unlock_mechanism = "abc"
64
+ end
65
+ ```
66
+
67
+ Or it can be a lambda function:
68
+ ```
69
+ PseudoKiosk::Config.configure do |config|
70
+ config.unlock_mechanism = ->(controller_context, params) {
71
+ return Digest::SHA256.base64digest(params[:passcode]) == controller_context.current_user.passcode_hash ? true : false
72
+ }
73
+ end
74
+ ```
75
+
76
+ The lambda function receives an instance of the controller which can be used to call functions such as current_user or session and all the params passed from the authentication unlock action. By default, the only parameter passed is `passcode`.
77
+
78
+
79
+ If you wish to override the default unlock screen, copy the [built in view](https://github.com/jonmchan/pseudo_kiosk/blob/master/app/views/pseudo_kiosk/authentication/unlock.html.erb) and put it in `app/views/pseudo_kiosk/authentication/unlock.html.erb`. Edit it to your heart's content.
80
+
81
+ ### Core Functions
82
+
83
+ You can call any of these functions to go in and out of kiosk mode (refer to [code documentation](https://github.com/jonmchan/pseudo_kiosk/blob/master/lib/pseudo_kiosk/controller.rb))
84
+
85
+ * pseudo_kiosk_start(url_whitelist, unauthorized_endpoint_redirect_url)
86
+ * pseudo_kiosk_exit(unlock_redirect_url)
87
+ * clear_pseudo_kiosk_session
88
+
89
+
90
+ ## Contributing
91
+ Feel free to submit PRs or Issues to the project's github page - https://github.com/jonmchan/pseudo_kiosk.
92
+
93
+ ## License
94
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -0,0 +1,27 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'PseudoKiosk'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.md')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+ APP_RAKEFILE = File.expand_path("spec/dummy/Rakefile", __dir__)
18
+ load 'rails/tasks/engine.rake'
19
+
20
+ load 'rails/tasks/statistics.rake'
21
+
22
+ require 'bundler/gem_tasks'
23
+
24
+ require 'rspec/core/rake_task'
25
+ RSpec::Core::RakeTask.new(:spec)
26
+
27
+ task default: :spec
@@ -0,0 +1,2 @@
1
+ //= link_directory ../javascripts/pseudo_kiosk .js
2
+ //= link_directory ../stylesheets/pseudo_kiosk .css
@@ -0,0 +1,14 @@
1
+ // This is a manifest file that'll be compiled into application.js, which will include all the files
2
+ // listed below.
3
+ //
4
+ // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5
+ // or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
6
+ //
7
+ // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8
+ // compiled file. JavaScript code in this file should be added after the last require_* statement.
9
+ //
10
+ // Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
11
+ // about supported directives.
12
+ //
13
+ //= require rails-ujs
14
+ //= require_tree .
@@ -0,0 +1,2 @@
1
+ // Place all the behaviors and hooks related to the matching controller here.
2
+ // All this logic will automatically be available in application.js.
@@ -0,0 +1,15 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the bottom of the
9
+ * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
10
+ * files in this directory. Styles in this file should be added after the last require_* statement.
11
+ * It is generally better to create a new file per style scope.
12
+ *
13
+ *= require_tree .
14
+ *= require_self
15
+ */
@@ -0,0 +1,4 @@
1
+ /*
2
+ Place all the styles related to the matching controller here.
3
+ They will automatically be included in application.css.
4
+ */
@@ -0,0 +1,5 @@
1
+ module PseudoKiosk
2
+ class ApplicationController < ActionController::Base
3
+ protect_from_forgery with: :exception, prepend: true
4
+ end
5
+ end
@@ -0,0 +1,37 @@
1
+ class PseudoKiosk::AuthenticationController < ApplicationController
2
+ skip_before_action :verify_authenticity_token
3
+ def unlock
4
+ unless session[:pseudo_kiosk_enabled]
5
+ redirect_back(fallback_location: root_path)
6
+ return
7
+ end
8
+ render :layout => false
9
+ end
10
+
11
+ def process_submit
12
+ unless session[:pseudo_kiosk_enabled]
13
+ redirect_back(fallback_location: root_path)
14
+ return
15
+ end
16
+ if PseudoKiosk::Config.unlock_mechanism.nil?
17
+ raise "PseudoKiosk::Config.unlock_mechanism is missing!"
18
+ elsif PseudoKiosk::Config.unlock_mechanism.is_a? String
19
+ PseudoKiosk::Config.unlock_mechanism == params[:passcode] ? unlock_success : unlock_fail
20
+ elsif PseudoKiosk::Config.unlock_mechanism.is_a? Proc
21
+ PseudoKiosk::Config.unlock_mechanism.call(self, params) ? unlock_success : unlock_fail
22
+ else
23
+ raise "No clue how to use an PseudoKiosk::Config.unlock_mechanism that is a #{PseudoKiosk::Config.unlock_mechanism.class}!"
24
+ end
25
+ end
26
+
27
+ private
28
+ def unlock_success
29
+ redirect_url = session[:pseudo_kiosk_unlock_redirect_url]
30
+ clear_pseudo_kiosk_session
31
+ redirect_to redirect_url
32
+ end
33
+
34
+ def unlock_fail
35
+ redirect_to(PseudoKiosk::Engine.routes.url_helpers.pseudo_kiosk_authentication_unlock_path(failed: "true"))
36
+ end
37
+ end
@@ -0,0 +1,4 @@
1
+ module PseudoKiosk
2
+ module ApplicationHelper
3
+ end
4
+ end
@@ -0,0 +1,2 @@
1
+ module PseudoKiosk::AuthenticationHelper
2
+ end
@@ -0,0 +1,16 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Kiosk lock</title>
5
+ <%= csrf_meta_tags %>
6
+ <%= csp_meta_tag %>
7
+
8
+ <%= stylesheet_link_tag "pseudo_kiosk/application", media: "all" %>
9
+ <%= javascript_include_tag "pseudo_kiosk/application" %>
10
+ </head>
11
+ <body>
12
+
13
+ <%= yield %>
14
+
15
+ </body>
16
+ </html>
@@ -0,0 +1,2 @@
1
+ <h1>PseudoKiosk::Authentication#process_submit</h1>
2
+ <p>Find me in app/views/pseudo_kiosk/authentication/process_submit.html.erb</p>
@@ -0,0 +1,259 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+
6
+ <%= csrf_meta_tags %>
7
+ <%= csp_meta_tag %>
8
+ <title>Operator Unlock</title>
9
+
10
+ <meta name="viewport" content="width=device-width">
11
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/5.0.0/normalize.min.css">
12
+
13
+ <style>
14
+ .pullee {
15
+ width: 10rem;
16
+ appearance: none;
17
+ }
18
+ .pullee:active::-webkit-slider-thumb {
19
+ appearance: none;
20
+ transform: scale(1.1);
21
+ cursor: -webkit-grabbing;
22
+ cursor: -moz-grabbing;
23
+ }
24
+ .pullee:active::-moz-range-thumb {
25
+ border: 0;
26
+ transform: scale(1.1);
27
+ cursor: -webkit-grabbing;
28
+ cursor: -moz-grabbing;
29
+ }
30
+ .pullee:active::-ms-thumb {
31
+ transform: scale(1.1);
32
+ cursor: -webkit-grabbing;
33
+ cursor: -moz-grabbing;
34
+ }
35
+ .pullee:focus {
36
+ outline: none;
37
+ }
38
+ .pullee::-webkit-slider-thumb {
39
+ appearance: none;
40
+ display: block;
41
+ width: 1rem;
42
+ height: 1rem;
43
+ border-radius: 50%;
44
+ background: #5990DD;
45
+ transform-origin: 50% 50%;
46
+ transform: scale(1);
47
+ transition: transform ease-out 100ms;
48
+ cursor: -webkit-grab;
49
+ cursor: -moz-grab;
50
+ }
51
+ .pullee::-moz-range-thumb {
52
+ border: 0;
53
+ display: block;
54
+ width: 1rem;
55
+ height: 1rem;
56
+ border-radius: 50%;
57
+ background: #5990DD;
58
+ transform-origin: 50% 50%;
59
+ transform: scale(1);
60
+ transition: transform ease-out 100ms;
61
+ cursor: -webkit-grab;
62
+ cursor: -moz-grab;
63
+ }
64
+ .pullee::-ms-thumb {
65
+ display: block;
66
+ width: 1rem;
67
+ height: 1rem;
68
+ border-radius: 50%;
69
+ background: #5990DD;
70
+ transform-origin: 50% 50%;
71
+ transform: scale(1);
72
+ transition: transform ease-out 100ms;
73
+ cursor: -webkit-grab;
74
+ cursor: -moz-grab;
75
+ }
76
+ .pullee::-webkit-slider-runnable-track {
77
+ height: 1rem;
78
+ padding: .25rem;
79
+ box-sizing: content-box;
80
+ border-radius: 1rem;
81
+ background-color: #DDE0E3;
82
+ }
83
+ .pullee::-moz-range-track {
84
+ height: 1rem;
85
+ padding: .25rem;
86
+ box-sizing: content-box;
87
+ border-radius: 1rem;
88
+ background-color: #DDE0E3;
89
+ }
90
+ .pullee::-moz-focus-outer {
91
+ border: 0;
92
+ }
93
+ .pullee::-ms-track {
94
+ border: 0;
95
+ height: 1rem;
96
+ padding: .25rem;
97
+ box-sizing: content-box;
98
+ border-radius: 1rem;
99
+ background-color: #DDE0E3;
100
+ color: transparent;
101
+ }
102
+ .pullee::-ms-fill-lower, .pullee::-ms-fill-upper {
103
+ background-color: transparent;
104
+ }
105
+ .pullee::-ms-tooltip {
106
+ display: none;
107
+ }
108
+
109
+ html {
110
+ font-size: 32px;
111
+ text-align: center;
112
+ }
113
+
114
+ h1 {
115
+ font-size: 0.8rem;
116
+ text-transform: uppercase;
117
+ letter-spacing: 1.25px;
118
+ }
119
+
120
+ h2 {
121
+ font-size: 0.6rem;
122
+ text-transform: uppercase;
123
+ letter-spacing: 1.25px;
124
+ }
125
+
126
+ input[type=submit] {
127
+ font-size: 0.8rem;
128
+ text-transform: uppercase;
129
+ letter-spacing: 1.25px;
130
+ margin: .65em;
131
+ }
132
+
133
+ .center-xy {
134
+ position: absolute;
135
+ top: 50%;
136
+ left: 50%;
137
+ transform: translate(-50%, -50%);
138
+ }
139
+
140
+ <% if params[:failed] %>
141
+ #pass_window {
142
+ display: initial;
143
+ }
144
+ #invalid {
145
+ display: initial;
146
+ font-size: 0.55rem;
147
+ color: red;
148
+ text-transform: uppercase;
149
+ letter-spacing: 1.25px;
150
+ }
151
+
152
+ #explanation_window {
153
+ display: none;
154
+ }
155
+ <% else %>
156
+ #pass_window {
157
+ display: none;
158
+ }
159
+ #invalid {
160
+ display: none;
161
+ }
162
+
163
+ #explanation_window {
164
+ display: initial;
165
+ }
166
+ <% end %>
167
+ </style>
168
+ <script>
169
+ window.console = window.console || function(t) {};
170
+ </script>
171
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script>
172
+ <script>
173
+ if (document.location.search.match(/type=embed/gi)) {
174
+ window.parent.postMessage("resize", "*");
175
+ }
176
+ </script>
177
+ </head>
178
+
179
+ <body translate="no">
180
+ <div id="explanation_window" class="center-xy">
181
+ <h1>Thank you for your input!</h1>
182
+ <h2>Please pass the device back to the operator</h2>
183
+ <h1>Slide to Unlock</h1>
184
+ <input type="range" value="0" class="pullee" />
185
+ </div>
186
+ <% # This is bad... I am having a problem using the named routes within the rails engine plugin %>
187
+ <%= form_tag 'process_submit', authenticity_token: true do %>
188
+ <div id="pass_window" class="center-xy">
189
+ <h1>Passcode:</h1>
190
+ <div id="invalid">Invalid Passcode! Please try again.</div>
191
+ <div><input type="password" name="passcode" style="text-align: center;"></div>
192
+ <div><input type="submit"></div>
193
+ <% end %>
194
+ </div>
195
+ <script id="rendered-js">
196
+ var inputRange = document.getElementsByClassName('pullee')[0],
197
+ maxValue = 150, // the higher the smoother when dragging
198
+ speed = 12, // thanks to @pixelass for this
199
+ currValue, rafID;
200
+
201
+ // set min/max value
202
+ inputRange.min = 0;
203
+ inputRange.max = maxValue;
204
+
205
+ // listen for unlock
206
+ function unlockStartHandler() {
207
+ // clear raf if trying again
208
+ window.cancelAnimationFrame(rafID);
209
+
210
+ // set to desired value
211
+ currValue = +this.value;
212
+ }
213
+
214
+ function unlockEndHandler() {
215
+
216
+ // store current value
217
+ currValue = +this.value;
218
+
219
+ // determine if we have reached success or not
220
+ if(currValue >= maxValue) {
221
+ successHandler();
222
+ }
223
+ else {
224
+ rafID = window.requestAnimationFrame(animateHandler);
225
+ }
226
+ }
227
+
228
+ // handle range animation
229
+ function animateHandler() {
230
+
231
+ // update input range
232
+ inputRange.value = currValue;
233
+
234
+ // determine if we need to continue
235
+ if(currValue > -1) {
236
+ window.requestAnimationFrame(animateHandler);
237
+ }
238
+
239
+ // decrement value
240
+ currValue = currValue - speed;
241
+ }
242
+
243
+ // handle successful unlock
244
+ function successHandler() {
245
+ document.getElementById("pass_window").style.display = "block";
246
+ document.getElementById("explanation_window").style.display = "none";
247
+
248
+ // reset input range
249
+ inputRange.value = 0;
250
+ };
251
+
252
+ // bind events
253
+ inputRange.addEventListener('mousedown', unlockStartHandler, false);
254
+ inputRange.addEventListener('mousestart', unlockStartHandler, false);
255
+ inputRange.addEventListener('mouseup', unlockEndHandler, false);
256
+ inputRange.addEventListener('touchend', unlockEndHandler, false);
257
+ </script>
258
+ </body>
259
+ </html>
@@ -0,0 +1,6 @@
1
+ PseudoKiosk::Engine.routes.draw do
2
+ namespace :pseudo_kiosk, path: '' do
3
+ get 'authentication/unlock'
4
+ post 'authentication/process_submit'
5
+ end
6
+ end
@@ -0,0 +1,13 @@
1
+ require "pseudo_kiosk/engine"
2
+
3
+ module PseudoKiosk
4
+ autoload(:Config, 'pseudo_kiosk/config')
5
+ require 'pseudo_kiosk/controller'
6
+ module TestHelpers
7
+ require 'pseudo_kiosk/test_helpers/internal'
8
+
9
+ module Internal
10
+ require 'pseudo_kiosk/test_helpers/internal/rails'
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,46 @@
1
+ module PseudoKiosk
2
+ module Config
3
+ class << self
4
+ # accepts a lambda function or string
5
+ # if lambda function is passed, instance of controller
6
+ # is passed to lambda for access to helper functions like
7
+ # current_user
8
+ attr_accessor :unlock_mechanism
9
+
10
+ def init!
11
+ @defaults = {
12
+ :@unlock_mechanism => nil,
13
+ }
14
+ end
15
+
16
+ # Resets all configuration options to their default values.
17
+ def reset!
18
+ @defaults.each do |k, v|
19
+ instance_variable_set(k, v)
20
+ end
21
+ end
22
+
23
+ def update!
24
+ @defaults.each do |k, v|
25
+ instance_variable_set(k, v) unless instance_variable_defined?(k)
26
+ end
27
+ end
28
+
29
+ def user_config(&blk)
30
+ block_given? ? @user_config = blk : @user_config
31
+ end
32
+
33
+ def configure(&blk)
34
+ @configure_blk = blk
35
+ @configure_blk.call(self)
36
+ end
37
+
38
+ def configure!
39
+ @configure_blk.call(self) if @configure_blk
40
+ end
41
+ end
42
+
43
+ init!
44
+ reset!
45
+ end
46
+ end
@@ -0,0 +1,88 @@
1
+ module PseudoKiosk
2
+ module Controller
3
+ # code borrowed from Sorcery (https://github.com/Sorcery/sorcery/blob/ae83ac3181aed9696bf78ceabcce96bf735fd7ea/lib/sorcery/controller.rb)
4
+ def self.included(klass)
5
+ klass.class_eval do
6
+ include InstanceMethods
7
+ end
8
+ #Config.update!
9
+ #Config.configure!
10
+ end
11
+
12
+ module InstanceMethods
13
+ # To be used in before_action in the application_controller.
14
+ # If pseudo_kiosk enabled, all endpoints that are not in the kiosk_whitelist
15
+ # will not allowed to be accessed
16
+ def secure_pseudo_kiosk
17
+ # this needs to go to the unlock screen
18
+ # binding.pry if request.path_info == test_work_flow_complete_step3_privilege_path
19
+ if session[:pseudo_kiosk_enabled]
20
+ whitelist = session[:pseudo_kiosk_whitelist].is_a?(Array) ? session[:pseudo_kiosk_whitelist] : [session[:pseudo_kiosk_whitelist]]
21
+
22
+ return if session[:pseudo_kiosk_unauthorized_endpoint_redirect_url].nil? && (params['controller'] == 'pseudo_kiosk/authentication')
23
+ whitelist.each do |allowed_url|
24
+ next if allowed_url.nil?
25
+ if allowed_url.is_a? Regexp
26
+ return if allowed_url =~ request.path_info
27
+ elsif allowed_url.start_with? "(?-mix:"
28
+ return if Regexp.new(allowed_url) =~ request.path_info
29
+ else
30
+ return if allowed_url == request.path_info
31
+ end
32
+ end
33
+
34
+ # need to either redirect to unauthorized_endpoint_redirect_url or allow user to break out
35
+ if session[:pseudo_kiosk_unauthorized_endpoint_redirect_url].nil?
36
+ session[:pseudo_kiosk_unlock_redirect_url] = request.path_info
37
+
38
+ redirect_to(pseudo_kiosk_engine.routes.url_helpers.pseudo_kiosk_authentication_unlock_path)
39
+ else
40
+ redirect_to(session[:pseudo_kiosk_unauthorized_endpoint_redirect_url])
41
+ end
42
+ end
43
+ end
44
+
45
+ # Locks the session down for unprivileged usage
46
+ #
47
+ # Params:
48
+ # url_whitelist - an array of url strings or regex searches
49
+ # of endpoints allowed to be visited during kiosk lock mode
50
+ #
51
+ # unauthorized_endpoint_redirect - url to redirect to if user navigates
52
+ # to a url outside of the url_whitelist.
53
+ # If nil, the unlock screen will be shown when navigating to urls
54
+ # outside of the whitelist; upon successful authentication, the user
55
+ # will be redirected to current endpoint
56
+ def pseudo_kiosk_start(url_whitelist, unauthorized_endpoint_redirect_url)
57
+ session[:pseudo_kiosk_enabled] = true
58
+ session[:pseudo_kiosk_whitelist] = url_whitelist
59
+ session[:pseudo_kiosk_unauthorized_endpoint_redirect_url] = unauthorized_endpoint_redirect_url
60
+ end
61
+
62
+
63
+ # redirects to pseudo_kiosk unlock screen. When successfully unlocked, the browser is
64
+ # redirected to the unlock_redirect_url
65
+ def pseudo_kiosk_exit(unlock_redirect_url)
66
+ session[:pseudo_kiosk_unlock_redirect_url] = unlock_redirect_url
67
+
68
+ # clear the whitelist here, because we want to only allow
69
+ # the session to be given back to the privileged user and
70
+ # for no further operations to be done in the whitelist area
71
+ session.delete(:pseudo_kiosk_whitelist)
72
+ session.delete(:pseudo_kiosk_unauthorized_endpoint_redirect_url)
73
+
74
+ redirect_to(PseudoKiosk::Engine.routes.url_helpers.pseudo_kiosk_authentication_unlock_path)
75
+ end
76
+
77
+ # clear all pseudo_kiosk session variables; this is an internal function
78
+ # Most likely pseudo_kiosk_exit is what should be used, unless there is some usecase
79
+ # where you want to instantly exit the pseudo_kiosk session without going through authentication
80
+ def clear_pseudo_kiosk_session
81
+ session.delete(:pseudo_kiosk_enabled)
82
+ session.delete(:pseudo_kiosk_whitelist)
83
+ session.delete(:pseudo_kiosk_unauthorized_endpoint_redirect_url)
84
+ session.delete(:pseudo_kiosk_unlock_redirect_url)
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,13 @@
1
+ module PseudoKiosk
2
+ class Engine < ::Rails::Engine
3
+ #config.pseudo_kiosk = PseudoKiosk::Config
4
+ # Do we need this for what we're doing?
5
+ # isolate_namespace PseudoKiosk
6
+
7
+ initializer 'extend Controller with PseudoKiosk' do
8
+ if defined?(ActionController::Base)
9
+ ActionController::Base.send(:include, PseudoKiosk::Controller)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,79 @@
1
+ module PseudoKiosk
2
+ module TestHelpers
3
+ # Internal TestHelpers are used to test the gem, internally, and should not be used to test apps *using* sorcery.
4
+ # This file will be included in the spec_helper file.
5
+ module Internal
6
+ def self.included(_base)
7
+ # # reducing default cost for specs speed
8
+ # CryptoProviders::BCrypt.class_eval do
9
+ # class << self
10
+ # def cost
11
+ # 1
12
+ # end
13
+ # end
14
+ # end
15
+ end
16
+
17
+ # a patch to fix a bug in testing that happens when you 'destroy' a session twice.
18
+ # After the first destroy, the session is an ordinary hash, and then when destroy
19
+ # is called again there's an exception.
20
+ class ::Hash # rubocop:disable Style/ClassAndModuleChildren
21
+ def destroy
22
+ clear
23
+ end
24
+ end
25
+
26
+ def build_new_user(attributes_hash = nil)
27
+ user_attributes_hash = attributes_hash || { username: 'gizmo', email: 'bla@bla.com', password: 'secret' }
28
+ @user = User.new(user_attributes_hash)
29
+ end
30
+
31
+ def create_new_user(attributes_hash = nil)
32
+ @user = build_new_user(attributes_hash)
33
+ @user.sorcery_adapter.save(raise_on_failure: true)
34
+ @user
35
+ end
36
+
37
+ def create_new_external_user(provider, attributes_hash = nil)
38
+ user_attributes_hash = attributes_hash || { username: 'gizmo' }
39
+ @user = User.new(user_attributes_hash)
40
+ @user.sorcery_adapter.save(raise_on_failure: true)
41
+ @user.authentications.create!(provider: provider, uid: 123)
42
+ @user
43
+ end
44
+
45
+ def custom_create_new_external_user(provider, authentication_class, attributes_hash = nil)
46
+ authentication_association = authentication_class.name.underscore.pluralize
47
+
48
+ user_attributes_hash = attributes_hash || { username: 'gizmo' }
49
+ @user = User.new(user_attributes_hash)
50
+ @user.sorcery_adapter.save(raise_on_failure: true)
51
+ @user.send(authentication_association).create!(provider: provider, uid: 123)
52
+ @user
53
+ end
54
+
55
+ def sorcery_model_property_set(property, *values)
56
+ User.class_eval do
57
+ sorcery_config.send(:"#{property}=", *values)
58
+ end
59
+ end
60
+
61
+ def update_model(&block)
62
+ User.class_exec(&block)
63
+ end
64
+
65
+ private
66
+
67
+ # reload user class between specs
68
+ # so it will be possible to test the different submodules in isolation
69
+ def reload_user_class
70
+ User && Object.send(:remove_const, 'User')
71
+ load 'user.rb'
72
+
73
+ return unless User.respond_to?(:reset_column_information)
74
+
75
+ User.reset_column_information
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,22 @@
1
+ module PseudoKiosk
2
+ module TestHelpers
3
+ module Internal
4
+ module Rails
5
+ def pseudo_kiosk_reload!
6
+ PseudoKiosk::Config.init!
7
+ PseudoKiosk::Config.reset!
8
+
9
+ ActionController::Base.send(:include, PseudoKiosk::Controller)
10
+ end
11
+
12
+ def pseudo_kiosk_config_property_set(property, value)
13
+ ::PseudoKiosk::Config.send(:"#{property}=", value)
14
+ end
15
+
16
+ # def pseudo_kiosk_config_external_property_set(provider, property, value)
17
+ # ::PseudoKiosk::Config.send(provider).send(:"#{property}=", value)
18
+ # end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,3 @@
1
+ module PseudoKiosk
2
+ VERSION = '0.1.0'
3
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :pseudo_kiosk do
3
+ # # Task goes here
4
+ # end
metadata ADDED
@@ -0,0 +1,127 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: pseudo_kiosk
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Jonathan Chan
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2019-10-26 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 5.2.3
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 5.2.3
27
+ - !ruby/object:Gem::Dependency
28
+ name: sqlite3
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec-rails
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: pry
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: PseudoKiosk gives the ability to limit access to the application during
70
+ workflows which involve physically passing a device with elevated permissions to
71
+ an unknown or untrusted user.
72
+ email:
73
+ - jc@jmccc.com
74
+ executables: []
75
+ extensions: []
76
+ extra_rdoc_files: []
77
+ files:
78
+ - MIT-LICENSE
79
+ - README.md
80
+ - Rakefile
81
+ - app/assets/config/pseudo_kiosk_manifest.js
82
+ - app/assets/javascripts/pseudo_kiosk/application.js
83
+ - app/assets/javascripts/pseudo_kiosk/authentication.js
84
+ - app/assets/stylesheets/pseudo_kiosk/application.css
85
+ - app/assets/stylesheets/pseudo_kiosk/authentication.css
86
+ - app/controllers/pseudo_kiosk/application_controller.rb
87
+ - app/controllers/pseudo_kiosk/authentication_controller.rb
88
+ - app/helpers/pseudo_kiosk/application_helper.rb
89
+ - app/helpers/pseudo_kiosk/authentication_helper.rb
90
+ - app/views/layouts/pseudo_kiosk/application.html.erb
91
+ - app/views/pseudo_kiosk/authentication/process_submit.html.erb
92
+ - app/views/pseudo_kiosk/authentication/unlock.html.erb
93
+ - config/routes.rb
94
+ - lib/pseudo_kiosk.rb
95
+ - lib/pseudo_kiosk/config.rb
96
+ - lib/pseudo_kiosk/controller.rb
97
+ - lib/pseudo_kiosk/engine.rb
98
+ - lib/pseudo_kiosk/test_helpers/internal.rb
99
+ - lib/pseudo_kiosk/test_helpers/internal/rails.rb
100
+ - lib/pseudo_kiosk/version.rb
101
+ - lib/tasks/pseudo_kiosk_tasks.rake
102
+ homepage: https://github.com/jonmchan/pseudo_kiosk
103
+ licenses:
104
+ - MIT
105
+ metadata:
106
+ allowed_push_host: https://rubygems.org
107
+ post_install_message:
108
+ rdoc_options: []
109
+ require_paths:
110
+ - lib
111
+ required_ruby_version: !ruby/object:Gem::Requirement
112
+ requirements:
113
+ - - ">="
114
+ - !ruby/object:Gem::Version
115
+ version: 2.5.0
116
+ required_rubygems_version: !ruby/object:Gem::Requirement
117
+ requirements:
118
+ - - ">="
119
+ - !ruby/object:Gem::Version
120
+ version: '0'
121
+ requirements: []
122
+ rubygems_version: 3.0.3
123
+ signing_key:
124
+ specification_version: 4
125
+ summary: PseudoKiosk provides the ability to lock down a rails application to only
126
+ a specified whitelist of endpoints during a session.
127
+ test_files: []