pseudo_kiosk 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: []