panda_pal 5.3.6.beta2 → 5.3.10
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.
- checksums.yaml +4 -4
- data/README.md +15 -2
- data/app/controllers/panda_pal/lti_v1_p0_controller.rb +1 -1
- data/app/controllers/panda_pal/lti_v1_p3_controller.rb +8 -4
- data/app/lib/lti_xml/base_platform.rb +7 -2
- data/app/lib/panda_pal/launch_url_helpers.rb +15 -8
- data/app/models/panda_pal/organization_concerns/settings_validation.rb +14 -0
- data/config/initializers/apartment.rb +3 -1
- data/config/routes.rb +1 -0
- data/lib/panda_pal.rb +1 -0
- data/lib/panda_pal/helpers/controller_helper.rb +5 -1
- data/lib/panda_pal/helpers/route_helper.rb +6 -0
- data/lib/panda_pal/version.rb +1 -1
- data/panda_pal.gemspec +1 -0
- metadata +18 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 42e9ffbf3704935100156e28b5d3f2490fba75a5974b352f0092c14bb8b87ffb
|
4
|
+
data.tar.gz: 5d511a85fe356dfe659ecaacfc7023315f649947ff483c6969e253802549e825
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a4d2a7242e203c4c86866ff7efb3ba211c2b3b7f41463b776785371e06997470fdee569ed4e4ba0025a7eef6198bb067e1fdf71fc8b7c9307bf26c1d343de7db
|
7
|
+
data.tar.gz: 7c3f0facf0767b7afea02ad0368bf6a0d79c8522109289e463a95719cd7f3762a34b5ad641499ff96871815f2db1ec76f192dd6221936d3af2586399a402bf1f
|
data/README.md
CHANGED
@@ -26,7 +26,8 @@ LTI 1.3 has some additional configuration steps required to setup an LTI:
|
|
26
26
|
|
27
27
|
1. If you're running Canvas locally, make sure the `config/redis.yml` and `config/dynamic_settings.yml` files exist in Canvas.
|
28
28
|
2. In prod, you'll need to generate a RSA Private Key for the LTI to use. You can set the `LTI_PRIVATE_KEY` ENV variable, or manually set `PandaPal.lti_private_key = OpenSSL::PKey::RSA.new(key)`.
|
29
|
-
3.
|
29
|
+
3. Make sure you have Redis installed and linked correctly
|
30
|
+
4. Your PandaPal::Organization's `key` should be `CLIENT_ID/DEPLOYMENT_ID` (which can be found in Canvas). If a Deployment ID is not given, the key should just be `CLIENT_ID`.
|
30
31
|
|
31
32
|
### Launch URL property
|
32
33
|
LTI Spec: `The launch_url contains the URL to which the LTI Launch is to be sent. The secure_launch_url is the URL to use if secure http is required. One of either the launch_url or the secure_launch_url must be specified.`
|
@@ -92,10 +93,22 @@ The following routes should be added to the routes.rb file of the implementing L
|
|
92
93
|
```ruby
|
93
94
|
# config/routes.rb
|
94
95
|
mount PandaPal::Engine, at: '/lti'
|
95
|
-
lti_nav account_navigation: 'accounts#launch' # Use lti_nav to provide a custom Launch implementation, otherwise use the url: param of stage_navigation to let PandaPal handle launch.
|
96
96
|
root to: 'panda_pal/lti#launch'
|
97
|
+
|
98
|
+
# Add Launch Endpoints:
|
99
|
+
lti_nav account_navigation: 'accounts#launch', auto_launch: false # (LTI <1.3 Default)
|
100
|
+
# -- OR --
|
101
|
+
scope '/organizations/:organization_id' do
|
102
|
+
lti_nav account_navigation: 'accounts#launch_landing', auto_launch: true # (LTI 1.3 Default)
|
103
|
+
lti_nav account_navigation: 'accounts#launch_landing' # Automatically sets auto_launch to true because :organization_id is part of the path
|
104
|
+
# ...
|
105
|
+
end
|
97
106
|
```
|
98
107
|
|
108
|
+
`auto_launch`: Setting to `true` will tell PandaPal to handle all of the launch details and session creation, and then pass off to
|
109
|
+
the defined action. Setting it to `false` indicates that the defined action handles launch validation and setup itself (this has been the legacy approach).
|
110
|
+
Because `auto_launch: false` is most similar to the previous behavior, it is the default for LTI 1.0/1.1 LTIs. For LTI 1.3 LTIs, `auto_launch: true` is the default. If not specified and `:organization_id` is detected in the Route Path, `auto_launch` will be set to `true`
|
111
|
+
|
99
112
|
## Implementating data segregation
|
100
113
|
This engine uses Apartment to keep data segregated between installations of the implementing LTI tool.
|
101
114
|
By default, it does this by inspecting the path of the request, and matching URLs containing `orgs` or `organizations`,
|
@@ -2,7 +2,7 @@ require_dependency "panda_pal/application_controller"
|
|
2
2
|
|
3
3
|
module PandaPal
|
4
4
|
class LtiV1P3Controller < ApplicationController
|
5
|
-
|
5
|
+
skip_before_action :verify_authenticity_token
|
6
6
|
before_action :validate_launch!, only: [:resource_link_request]
|
7
7
|
around_action :switch_tenant, only: [:resource_link_request]
|
8
8
|
|
@@ -55,11 +55,15 @@ module PandaPal
|
|
55
55
|
parsed_request_url = URI.parse(request_url)
|
56
56
|
|
57
57
|
mapped_placements = PandaPal.lti_paths.map do |k, opts|
|
58
|
-
opts = opts
|
59
|
-
opts.delete(:route_helper_key)
|
58
|
+
opts = LaunchUrlHelpers.normalize_lti_launch_desc(opts)
|
60
59
|
opts.merge!({
|
61
60
|
placement: k,
|
62
|
-
target_link_uri: LaunchUrlHelpers.absolute_launch_url(
|
61
|
+
target_link_uri: LaunchUrlHelpers.absolute_launch_url(
|
62
|
+
k.to_sym,
|
63
|
+
host: parsed_request_url,
|
64
|
+
launch_handler: v1p3_resource_link_request_path,
|
65
|
+
default_auto_launch: true
|
66
|
+
),
|
63
67
|
})
|
64
68
|
opts
|
65
69
|
end
|
@@ -85,8 +85,13 @@ module LtiXml
|
|
85
85
|
end
|
86
86
|
|
87
87
|
def ext_params(options, k)
|
88
|
-
options.
|
89
|
-
options[:url] = PandaPal::LaunchUrlHelpers.absolute_launch_url(
|
88
|
+
options = PandaPal::LaunchUrlHelpers.normalize_lti_launch_desc(options)
|
89
|
+
options[:url] = PandaPal::LaunchUrlHelpers.absolute_launch_url(
|
90
|
+
k.to_sym,
|
91
|
+
host: parsed_request_url,
|
92
|
+
launch_handler: :v1p0_launch_path,
|
93
|
+
default_auto_launch: false
|
94
|
+
)
|
90
95
|
options
|
91
96
|
end
|
92
97
|
end
|
@@ -1,22 +1,29 @@
|
|
1
1
|
module PandaPal
|
2
2
|
module LaunchUrlHelpers
|
3
|
-
def self.absolute_launch_url(launch_type, host:, launch_handler: nil)
|
3
|
+
def self.absolute_launch_url(launch_type, host:, launch_handler: nil, default_auto_launch: false)
|
4
4
|
opts = PandaPal.lti_paths[launch_type]
|
5
|
-
|
5
|
+
auto_launch = opts[:auto_launch] != nil ? opts[:auto_launch] : default_auto_launch
|
6
|
+
auto_launch = auto_launch && launch_handler.present?
|
6
7
|
|
7
|
-
|
8
|
-
|
9
|
-
if is_direct
|
10
|
-
return final_url if URI.parse(final_url).absolute?
|
11
|
-
return [host.to_s, final_url].join
|
12
|
-
else
|
8
|
+
if auto_launch
|
13
9
|
launch_handler = resolve_route(launch_handler) if launch_handler.is_a?(Symbol)
|
14
10
|
return add_url_params([host.to_s, launch_handler].join, {
|
15
11
|
launch_type: launch_type,
|
16
12
|
})
|
13
|
+
else
|
14
|
+
final_url = launch_url(opts, launch_type: launch_type)
|
15
|
+
return final_url if URI.parse(final_url).absolute?
|
16
|
+
return [host.to_s, final_url].join
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
|
+
def self.normalize_lti_launch_desc(opts)
|
21
|
+
opts = opts.dup
|
22
|
+
opts.delete(:route_helper_key)
|
23
|
+
opts.delete(:auto_launch)
|
24
|
+
opts
|
25
|
+
end
|
26
|
+
|
20
27
|
def self.launch_url(opts, launch_type: nil)
|
21
28
|
url = launch_route(opts, launch_type: launch_type)
|
22
29
|
url = resolve_url_symbol(url) if url.is_a?(Symbol)
|
@@ -99,6 +99,20 @@ module PandaPal
|
|
99
99
|
errors.concat(val_errors)
|
100
100
|
end
|
101
101
|
|
102
|
+
if settings.is_a?(Array)
|
103
|
+
if spec[:length].is_a?(Range)
|
104
|
+
errors << "#{human_path} should contain #{spec[:length]} items" unless spec[:length].include?(settings.count)
|
105
|
+
elsif spec[:length].is_a?(Numeric)
|
106
|
+
errors << "#{human_path} should contain exactly #{spec[:length]} items" unless spec[:length] == settings.count
|
107
|
+
end
|
108
|
+
|
109
|
+
if spec[:item] != nil
|
110
|
+
settings.each_with_index do |value, i|
|
111
|
+
validate_settings_level(settings[i], spec[:item], path: [*path, i], errors: errors)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
102
116
|
if settings.is_a?(Hash)
|
103
117
|
if spec[:properties] != nil
|
104
118
|
spec[:properties].each do |key, pspec|
|
@@ -10,7 +10,9 @@ Apartment.configure do |config|
|
|
10
10
|
end
|
11
11
|
|
12
12
|
Rails.application.config.middleware.use Apartment::Elevators::Generic, lambda { |request|
|
13
|
-
if
|
13
|
+
if request.path.starts_with?('/rails/active_storage/blobs/')
|
14
|
+
PandaPal::Organization.find_by(id: request.params['organization_id']).try(:name)
|
15
|
+
elsif match = request.path.match(/\/(?:orgs?|organizations?)\/(\d+)/)
|
14
16
|
PandaPal::Organization.find_by(id: match[1]).try(:name)
|
15
17
|
end
|
16
18
|
}
|
data/config/routes.rb
CHANGED
data/lib/panda_pal.rb
CHANGED
@@ -81,6 +81,7 @@ module PandaPal
|
|
81
81
|
|
82
82
|
def self.validate_lti_navigation(errors = [])
|
83
83
|
@@lti_navigation.each do |k, v|
|
84
|
+
next if v[:route_helper_key]
|
84
85
|
errors << "lti navigation '#{k}' does not have a Route!" unless (LaunchUrlHelpers.launch_url(k) rescue nil)
|
85
86
|
end
|
86
87
|
errors
|
@@ -39,7 +39,11 @@ module PandaPal::Helpers
|
|
39
39
|
|
40
40
|
def validate_v1p0_launch
|
41
41
|
authorized = false
|
42
|
-
|
42
|
+
# We should verify the timestamp is recent (within 5 minutes). The approved timestamp is part of the signature,
|
43
|
+
# so we don't need to worry about malicious users messing with it. We should deny requests that come too long
|
44
|
+
# after the approved timestamp.
|
45
|
+
good_timestamp = params['oauth_timestamp'] && params['oauth_timestamp'].to_i > Time.now.to_i - 300
|
46
|
+
if @organization = good_timestamp && params['oauth_consumer_key'] && PandaPal::Organization.find_by_key(params['oauth_consumer_key'])
|
43
47
|
sanitized_params = request.request_parameters
|
44
48
|
# These params come over with a safari-workaround launch. The authenticator doesn't like them, so clean them out.
|
45
49
|
safe_unexpected_params = ["full_win_launch_requested", "platform_redirect_url", "dummy_param"]
|
@@ -9,6 +9,12 @@ module PandaPal::Helpers::RouteHelper
|
|
9
9
|
path = "#{base_path}/#{nav.to_s}"
|
10
10
|
|
11
11
|
lti_options = options.delete(:lti_options) || {}
|
12
|
+
lti_options[:auto_launch] = options.delete(:auto_launch)
|
13
|
+
|
14
|
+
if lti_options[:auto_launch].nil?
|
15
|
+
lti_options[:auto_launch] = (@scope[:path] || '').include?(':organization_id')
|
16
|
+
end
|
17
|
+
|
12
18
|
lti_options[:route_helper_key] = path.split('/').reject(&:empty?).join('_')
|
13
19
|
post(path, options.dup, &block)
|
14
20
|
get(path, options.dup, &block)
|
data/lib/panda_pal/version.rb
CHANGED
data/panda_pal.gemspec
CHANGED
@@ -23,6 +23,7 @@ Gem::Specification.new do |s|
|
|
23
23
|
s.add_dependency 'attr_encrypted', '~> 3.0.0'
|
24
24
|
s.add_dependency 'secure_headers', '~> 6.1'
|
25
25
|
s.add_dependency 'json-jwt'
|
26
|
+
s.add_dependency 'httparty'
|
26
27
|
|
27
28
|
s.add_development_dependency 'sidekiq'
|
28
29
|
s.add_development_dependency 'sidekiq-scheduler'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: panda_pal
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 5.3.
|
4
|
+
version: 5.3.10
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Instructure ProServe
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-02-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -128,6 +128,20 @@ dependencies:
|
|
128
128
|
- - ">="
|
129
129
|
- !ruby/object:Gem::Version
|
130
130
|
version: '0'
|
131
|
+
- !ruby/object:Gem::Dependency
|
132
|
+
name: httparty
|
133
|
+
requirement: !ruby/object:Gem::Requirement
|
134
|
+
requirements:
|
135
|
+
- - ">="
|
136
|
+
- !ruby/object:Gem::Version
|
137
|
+
version: '0'
|
138
|
+
type: :runtime
|
139
|
+
prerelease: false
|
140
|
+
version_requirements: !ruby/object:Gem::Requirement
|
141
|
+
requirements:
|
142
|
+
- - ">="
|
143
|
+
- !ruby/object:Gem::Version
|
144
|
+
version: '0'
|
131
145
|
- !ruby/object:Gem::Dependency
|
132
146
|
name: sidekiq
|
133
147
|
requirement: !ruby/object:Gem::Requirement
|
@@ -298,9 +312,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
298
312
|
version: '0'
|
299
313
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
300
314
|
requirements:
|
301
|
-
- - "
|
315
|
+
- - ">="
|
302
316
|
- !ruby/object:Gem::Version
|
303
|
-
version:
|
317
|
+
version: '0'
|
304
318
|
requirements: []
|
305
319
|
rubygems_version: 3.0.3
|
306
320
|
signing_key:
|