coalescing_panda 5.0.1 → 5.0.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/app/assets/config/coalescing_panda/manifest.js +3 -0
- data/app/controllers/coalescing_panda/canvas_batches_controller.rb +2 -2
- data/app/controllers/coalescing_panda/lti_controller.rb +1 -1
- data/app/helpers/coalescing_panda/canvas_batches_helper.rb +1 -1
- data/app/models/coalescing_panda/json_with_indifferent_access.rb +13 -0
- data/app/models/coalescing_panda/persistent_session.rb +2 -1
- data/db/migrate/20131114150001_create_coalescing_panda_canvas_api_auths.rb +1 -1
- data/db/migrate/20131118211442_create_coalescing_panda_lti_accounts.rb +1 -1
- data/db/migrate/20131119165343_create_coalescing_panda_lti_nonces.rb +1 -1
- data/db/migrate/20140904223159_create_coalescing_panda_sessions.rb +1 -1
- data/db/migrate/20141119225319_create_coalescing_panda_terms.rb +1 -1
- data/db/migrate/20141119225721_create_coalescing_panda_courses.rb +1 -1
- data/db/migrate/20141120151432_create_coalescing_panda_sections.rb +1 -1
- data/db/migrate/20141120151940_create_coalescing_panda_assignments.rb +1 -1
- data/db/migrate/20141120152458_create_coalescing_panda_users.rb +1 -1
- data/db/migrate/20141120152546_create_coalescing_panda_submissions.rb +1 -1
- data/db/migrate/20141120153135_create_coalescing_panda_enrollments.rb +1 -1
- data/db/migrate/20141121174846_create_coalescing_panda_canvas_batches.rb +1 -1
- data/db/migrate/20141124160857_create_delayed_jobs.rb +1 -1
- data/db/migrate/20141208221740_add_submission_types_to_assignments.rb +1 -1
- data/db/migrate/20150106175418_add_group_category_id_to_assignment.rb +1 -1
- data/db/migrate/20150106180131_add_published_to_assignments.rb +1 -1
- data/db/migrate/20150107205405_create_coalescing_panda_groups.rb +1 -1
- data/db/migrate/20150107205413_create_coalescing_panda_group_memberships.rb +1 -1
- data/db/migrate/20150210180516_add_context_to_canvas_batch.rb +1 -1
- data/db/migrate/20150506183335_create_coalescing_panda_assignment_groups.rb +1 -1
- data/db/migrate/20150506192717_add_assignment_group_id_to_assignments.rb +1 -1
- data/db/migrate/20150526144713_add_account_to_canvas_batches.rb +1 -1
- data/db/migrate/20150602205257_add_option_to_canvas_batches.rb +1 -1
- data/db/migrate/20150708192717_add_group_moderator_to_group_memberships.rb +1 -1
- data/db/migrate/20150709192717_add_leader_id_to_groups.rb +1 -1
- data/db/migrate/20150714205405_create_coalescing_panda_group_categories.rb +1 -1
- data/db/migrate/20150811140030_add_fields_to_users.rb +1 -1
- data/db/migrate/20151209155923_add_refresh_settings_to_canvas_api_auth.rb +1 -1
- data/db/migrate/20160830183155_create_coalescing_panda_oauth_states.rb +1 -1
- data/db/migrate/20200528224505_create_coalescing_panda_persistent_session.rb +1 -1
- data/lib/coalescing_panda/controller_helpers.rb +40 -23
- data/lib/coalescing_panda/engine.rb +12 -42
- data/lib/coalescing_panda/misc_helper.rb +13 -0
- data/lib/coalescing_panda/secure_headers.rb +84 -0
- data/lib/coalescing_panda/version.rb +1 -1
- metadata +172 -163
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 671ec79eae7cb32383d46dd2fd788864463b8e3258a501e0cd16d6b98eb8b384
|
4
|
+
data.tar.gz: 6d7d5176bbba7a011279924cb17b3cc953d73bcf1fc516bdaf39df6b7db03f23
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2bd75383b5aa806226be52acebd1efa38b02103bf38d71784c4c7933f47dbbdf6e3dc919155e99783a08b760ab3a53caa51ef38213e9eaa8daf6d158778c181a
|
7
|
+
data.tar.gz: 425b73b527dd3598d1afbec15e9e67a306209d337f4cb944bf34dfa075b4f080f6c2d6306566b4764b8c5a87f0a262389d306c8d418a6dba802ea09f067428d0
|
@@ -12,13 +12,13 @@ module CoalescingPanda
|
|
12
12
|
@batch.status = 'Queued'
|
13
13
|
@batch.save
|
14
14
|
worker = CoalescingPanda::Workers::CourseMiner.new(@batch.context, @batch.options)
|
15
|
-
|
15
|
+
current_session_data[:canvas_batch_id] = worker.batch.id
|
16
16
|
worker.start(true)
|
17
17
|
redirect_to :back
|
18
18
|
end
|
19
19
|
|
20
20
|
def clear_batch_session
|
21
|
-
|
21
|
+
current_session_data[:canvas_batch_id] = nil
|
22
22
|
render nothing: true
|
23
23
|
end
|
24
24
|
end
|
@@ -17,7 +17,7 @@ module CoalescingPanda
|
|
17
17
|
lti_nav[:account][:text] = params[:account_navigation_label] if params[:account_navigation_label].present?
|
18
18
|
platform = 'canvas.instructure.com'
|
19
19
|
host = "#{request.scheme}://#{request.host_with_port}"
|
20
|
-
tc = IMS::LTI::
|
20
|
+
tc = IMS::LTI::ToolConfig.new(:title => lti_options[:title], :launch_url => ("#{host}#{lti_options[:launch_route]}") || 'ABC')
|
21
21
|
tc.set_ext_param(platform, :domain, request.host)
|
22
22
|
tc.set_ext_param(platform, :privacy_level, 'public')
|
23
23
|
tc.set_custom_param(:custom_canvas_role, '$Canvas.membership.roles')
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module CoalescingPanda
|
2
2
|
module CanvasBatchesHelper
|
3
3
|
def current_batch
|
4
|
-
@current_batch ||= CoalescingPanda::CanvasBatch.find_by_id(
|
4
|
+
@current_batch ||= CoalescingPanda::CanvasBatch.find_by_id(current_session_data[:canvas_batch_id])
|
5
5
|
end
|
6
6
|
end
|
7
7
|
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module CoalescingPanda
|
2
|
+
class JSONWithIndifferentAccess
|
3
|
+
def self.load(str)
|
4
|
+
return nil unless str.present?
|
5
|
+
parsed = JSON.parse(str)
|
6
|
+
parsed.is_a?(Hash) ? HashWithIndifferentAccess.new(parsed) : parsed
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.dump(obj)
|
10
|
+
JSON.dump(obj)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -1,10 +1,11 @@
|
|
1
1
|
module CoalescingPanda
|
2
2
|
class PersistentSession < ActiveRecord::Base
|
3
|
-
serialize :data,
|
3
|
+
serialize :data, JSONWithIndifferentAccess
|
4
4
|
belongs_to :coalescing_panda_lti_account, :class_name => 'CoalescingPanda::LtiAccount'
|
5
5
|
validates :coalescing_panda_lti_account_id, presence: true
|
6
6
|
|
7
7
|
after_initialize do
|
8
|
+
self.data ||= {}
|
8
9
|
self.session_key ||= SecureRandom.urlsafe_base64(60)
|
9
10
|
end
|
10
11
|
|
@@ -1,4 +1,4 @@
|
|
1
|
-
class CreateDelayedJobs <
|
1
|
+
class CreateDelayedJobs < CoalescingPanda::MiscHelper::MigrationClass
|
2
2
|
def self.up
|
3
3
|
create_table :delayed_jobs, :force => true do |table|
|
4
4
|
table.integer :priority, :default => 0, :null => false # Allows some jobs to jump to the front of the queue
|
@@ -1,4 +1,4 @@
|
|
1
|
-
class AddGroupCategoryIdToAssignment <
|
1
|
+
class AddGroupCategoryIdToAssignment < CoalescingPanda::MiscHelper::MigrationClass
|
2
2
|
def change
|
3
3
|
add_column :coalescing_panda_assignments, :group_category_id, :integer
|
4
4
|
add_column :coalescing_panda_assignments, :grade_group_students_individually, :boolean
|
@@ -1,4 +1,4 @@
|
|
1
|
-
class AddContextToCanvasBatch <
|
1
|
+
class AddContextToCanvasBatch < CoalescingPanda::MiscHelper::MigrationClass
|
2
2
|
def change
|
3
3
|
add_column :coalescing_panda_canvas_batches, :context_id, :integer
|
4
4
|
add_column :coalescing_panda_canvas_batches, :context_type, :string
|
@@ -1,4 +1,4 @@
|
|
1
|
-
class CreateCoalescingPandaAssignmentGroups <
|
1
|
+
class CreateCoalescingPandaAssignmentGroups < CoalescingPanda::MiscHelper::MigrationClass
|
2
2
|
def change
|
3
3
|
create_table :coalescing_panda_assignment_groups do |t|
|
4
4
|
t.belongs_to :coalescing_panda_course, null: false
|
@@ -1,4 +1,4 @@
|
|
1
|
-
class AddLeaderIdToGroups <
|
1
|
+
class AddLeaderIdToGroups < CoalescingPanda::MiscHelper::MigrationClass
|
2
2
|
def change
|
3
3
|
add_column :coalescing_panda_groups, :leader_id, :integer
|
4
4
|
add_foreign_key :coalescing_panda_groups, :coalescing_panda_users, column: :leader_id, primary_key: "id"
|
@@ -1,4 +1,4 @@
|
|
1
|
-
class CreateCoalescingPandaGroupCategories <
|
1
|
+
class CreateCoalescingPandaGroupCategories < CoalescingPanda::MiscHelper::MigrationClass
|
2
2
|
def change
|
3
3
|
create_table :coalescing_panda_group_categories do |t|
|
4
4
|
t.belongs_to :context, polymorphic: true
|
@@ -1,4 +1,4 @@
|
|
1
|
-
class AddRefreshSettingsToCanvasApiAuth <
|
1
|
+
class AddRefreshSettingsToCanvasApiAuth < CoalescingPanda::MiscHelper::MigrationClass
|
2
2
|
def change
|
3
3
|
add_column :coalescing_panda_canvas_api_auths, :refresh_token, :string
|
4
4
|
add_column :coalescing_panda_canvas_api_auths, :expires_at, :datetime
|
@@ -2,15 +2,32 @@ require 'browser'
|
|
2
2
|
|
3
3
|
module CoalescingPanda
|
4
4
|
module ControllerHelpers
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
alias_method :rails_session, :session
|
9
|
+
|
10
|
+
helper_method :encrypted_session_key, :current_session_data, :current_session
|
11
|
+
append_after_action :save_session, if: -> { @current_session && session_changed? }
|
12
|
+
end
|
13
|
+
|
14
|
+
class_methods do
|
15
|
+
def use_native_sessions
|
16
|
+
after_action do
|
17
|
+
rails_session['persistent_session_key'] = current_session.session_key if @current_session.present?
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
5
22
|
def current_session
|
6
|
-
@current_session ||= CoalescingPanda::PersistentSession.find_by(session_key: session_key) if session_key
|
7
|
-
@current_session ||= CoalescingPanda::PersistentSession.create_from_launch(params, current_lti_account.id)
|
23
|
+
@current_session ||= (CoalescingPanda::PersistentSession.find_by(session_key: session_key) if session_key)
|
24
|
+
@current_session ||= (CoalescingPanda::PersistentSession.create_from_launch(params, current_lti_account.id) if current_lti_account.present?)
|
8
25
|
@current_session
|
9
26
|
end
|
10
27
|
|
11
28
|
def current_lti_account
|
12
|
-
@account ||= CoalescingPanda::LtiAccount.find_by!(key: organization_key) if organization_key
|
13
|
-
@account ||= CoalescingPanda::LtiAccount.find_by(id: organization_id) if organization_id
|
29
|
+
@account ||= (CoalescingPanda::LtiAccount.find_by!(key: organization_key) if organization_key)
|
30
|
+
@account ||= (CoalescingPanda::LtiAccount.find_by(id: organization_id) if organization_id)
|
14
31
|
@account
|
15
32
|
end
|
16
33
|
|
@@ -83,42 +100,42 @@ module CoalescingPanda
|
|
83
100
|
end
|
84
101
|
|
85
102
|
def check_refresh_token
|
86
|
-
return unless
|
87
|
-
uri = BearcatUri.new(
|
88
|
-
api_auth = CanvasApiAuth.find_by(user_id:
|
89
|
-
@lti_account = LtiAccount.find_by(key:
|
103
|
+
return unless current_session_data['uri'] && current_session_data['user_id'] && current_session_data['oauth_consumer_key']
|
104
|
+
uri = BearcatUri.new(current_session_data['uri'])
|
105
|
+
api_auth = CanvasApiAuth.find_by(user_id: current_session_data['user_id'], api_domain: uri.api_domain)
|
106
|
+
@lti_account = LtiAccount.find_by(key: current_session_data['oauth_consumer_key'])
|
90
107
|
return if @lti_account.nil? || api_auth.nil? # Not all tools use oauth
|
91
108
|
|
92
109
|
refresh_token(uri, api_auth) if api_auth.expired?
|
93
110
|
rescue Footrest::HttpError::BadRequest
|
94
|
-
render_oauth2_page uri,
|
111
|
+
render_oauth2_page uri, current_session_data['user_id']
|
95
112
|
end
|
96
113
|
|
97
114
|
def set_session(launch_presentation_return_url)
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
115
|
+
current_session_data['user_id'] = params['user_id']
|
116
|
+
current_session_data['uri'] = launch_presentation_return_url
|
117
|
+
current_session_data['lis_person_sourcedid'] = params['lis_person_sourcedid']
|
118
|
+
current_session_data['oauth_consumer_key'] = params['oauth_consumer_key']
|
119
|
+
current_session_data['custom_canvas_account_id'] = params['custom_canvas_account_id']
|
103
120
|
end
|
104
121
|
|
105
122
|
def have_session?
|
106
|
-
if params['tool_consumer_instance_guid'] &&
|
123
|
+
if params['tool_consumer_instance_guid'] && current_session_data['user_id'] != params['user_id']
|
107
124
|
reset_session
|
108
125
|
logger.info("resetting session params")
|
109
|
-
|
126
|
+
current_session_data['user_id'] = params['user_id']
|
110
127
|
end
|
111
128
|
|
112
|
-
if (
|
113
|
-
uri = BearcatUri.new(
|
114
|
-
api_auth = CanvasApiAuth.find_by('user_id = ? and api_domain = ?',
|
129
|
+
if (current_session_data['user_id'] && current_session_data['uri'])
|
130
|
+
uri = BearcatUri.new(current_session_data['uri'])
|
131
|
+
api_auth = CanvasApiAuth.find_by('user_id = ? and api_domain = ?', current_session_data['user_id'], uri.api_domain)
|
115
132
|
if api_auth && !api_auth.expired?
|
116
133
|
@client = Bearcat::Client.new(token: api_auth.api_token, prefix: uri.prefix)
|
117
134
|
@client.user_profile 'self'
|
118
135
|
end
|
119
136
|
end
|
120
137
|
|
121
|
-
@lti_account = LtiAccount.find_by_key(
|
138
|
+
@lti_account = LtiAccount.find_by_key(current_session_data['oauth_consumer_key']) if current_session_data['oauth_consumer_key']
|
122
139
|
|
123
140
|
!!@client
|
124
141
|
rescue Footrest::HttpError::Unauthorized
|
@@ -129,8 +146,8 @@ module CoalescingPanda
|
|
129
146
|
authorized = false
|
130
147
|
if (@lti_account = params['oauth_consumer_key'] && LtiAccount.find_by_key(params['oauth_consumer_key']))
|
131
148
|
sanitized_params = sanitize_params
|
132
|
-
|
133
|
-
authorized =
|
149
|
+
@tp = IMS::LTI::ToolProvider.new(@lti_account.key, @lti_account.secret, sanitized_params)
|
150
|
+
authorized = @tp.valid_request?(request)
|
134
151
|
end
|
135
152
|
logger.info 'not authorized on tp valid request' unless authorized
|
136
153
|
authorized = authorized && (roles.count == 0 || (roles & lti_roles).count > 0)
|
@@ -198,7 +215,7 @@ module CoalescingPanda
|
|
198
215
|
if params[:encrypted_session_key]
|
199
216
|
return msg_encryptor.decrypt_and_verify(params[:encrypted_session_key])
|
200
217
|
end
|
201
|
-
params[:session_key] || session_key_header
|
218
|
+
params[:session_key] || session_key_header || rails_session['persistent_session_key']
|
202
219
|
end
|
203
220
|
|
204
221
|
def session_key_header
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'secure_headers'
|
2
|
+
require_relative './secure_headers'
|
2
3
|
|
3
4
|
module CoalescingPanda
|
4
5
|
class Engine < ::Rails::Engine
|
@@ -25,6 +26,10 @@ module CoalescingPanda
|
|
25
26
|
end
|
26
27
|
end
|
27
28
|
|
29
|
+
initializer 'coalescing_panda.assets' do |app|
|
30
|
+
app.config.assets.precompile << 'coalescing_panda/manifest.js'
|
31
|
+
end
|
32
|
+
|
28
33
|
initializer 'cloaescing_panda.route_helper' do |route|
|
29
34
|
ActionDispatch::Routing::Mapper.send :include, CoalescingPanda::RouteHelpers
|
30
35
|
end
|
@@ -38,56 +43,21 @@ module CoalescingPanda
|
|
38
43
|
end
|
39
44
|
|
40
45
|
initializer :secure_headers do |app|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
if Rails.env.development?
|
45
|
-
# Allow webpack-dev-server to work
|
46
|
-
connect_src << "http://localhost:3035"
|
47
|
-
connect_src << "ws://localhost:3035"
|
48
|
-
|
49
|
-
# Allow stuff like rack-mini-profiler to work in development:
|
50
|
-
# https://github.com/MiniProfiler/rack-mini-profiler/issues/327
|
51
|
-
# DON'T ENABLE THIS FOR PRODUCTION!
|
52
|
-
script_src << "'unsafe-eval'"
|
53
|
-
elsif CoalescingPanda.lti_options.has_key?(:allow_unsafe_eval) && CoalescingPanda.lti_options[:allow_unsafe_eval] == true
|
54
|
-
# For when code is returned from server and injected into dom. Need to have unsafe-eval or it won't work.
|
55
|
-
script_src << "'unsafe-eval'"
|
56
|
-
end
|
57
|
-
|
58
|
-
SecureHeaders::Configuration.default do |config|
|
59
|
-
# The default cookie headers aren't compatible with PandaPal cookies currently
|
60
|
-
config.cookies = { samesite: { none: true } }
|
61
|
-
|
62
|
-
if Rails.env.production?
|
63
|
-
config.cookies[:secure] = true
|
46
|
+
begin
|
47
|
+
::SecureHeaders::Configuration.default do |config|
|
48
|
+
CoalescingPanda::SecureHeaders.apply_defaults(config)
|
64
49
|
end
|
65
|
-
|
66
|
-
#
|
67
|
-
config.x_frame_options = "ALLOWALL"
|
68
|
-
|
69
|
-
config.x_content_type_options = "nosniff"
|
70
|
-
config.x_xss_protection = "1; mode=block"
|
71
|
-
config.referrer_policy = %w(origin-when-cross-origin strict-origin-when-cross-origin)
|
72
|
-
|
73
|
-
config.csp = {
|
74
|
-
default_src: %w('self'),
|
75
|
-
script_src: script_src,
|
76
|
-
# Certain CSS-in-JS libraries inline the CSS, so we need to use unsafe-inline for them
|
77
|
-
style_src: %w('self' 'unsafe-inline' blob: https://fonts.googleapis.com),
|
78
|
-
font_src: %w('self' data: https://fonts.gstatic.com),
|
79
|
-
connect_src: connect_src,
|
80
|
-
}
|
50
|
+
rescue ::SecureHeaders::Configuration::AlreadyConfiguredError
|
51
|
+
# The App already applied settings
|
81
52
|
end
|
82
53
|
|
83
|
-
SecureHeaders::Configuration.override(:safari_override) do |config|
|
54
|
+
::SecureHeaders::Configuration.override(:safari_override) do |config|
|
84
55
|
config.cookies = SecureHeaders::OPT_OUT
|
85
56
|
end
|
86
57
|
|
87
|
-
SecureHeaders::Configuration.override(:allow_inline_scripts) do |config|
|
58
|
+
::SecureHeaders::Configuration.override(:allow_inline_scripts) do |config|
|
88
59
|
config.csp[:script_src] << "'unsafe-inline'"
|
89
60
|
end
|
90
61
|
end
|
91
|
-
|
92
62
|
end
|
93
63
|
end
|