atomic_lti 1.9.0 → 1.10.0
Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 51f6a8b44052a79ca2848b1b32f9789ce2033c79cc168b6b43467429f463efe7
|
4
|
+
data.tar.gz: 9fc1c514d21fcec53c9b74d7b7a673d774052539f5313480ca12d0b3ce886643
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2d87e7f1666d050da989f2d10b017fbc90bc4f8e213f6082e1b45c96b907636ebfd4be09085bcc73bc251610e1b0e727b0204250906f1ef7a351cab50db502d8
|
7
|
+
data.tar.gz: d0cba43fba4d45d186dd45a804531409cf4d0b9a2453bb68e8ea9207048727c1e943147845034aa952991ce360a6380f44b90e479fd1317466fe9ac1d6eb7a44
|
@@ -31,6 +31,12 @@ module AtomicLti
|
|
31
31
|
|
32
32
|
NAMES_AND_ROLES_SERVICE_VERSIONS = ["2.0"].freeze
|
33
33
|
|
34
|
+
PLATFORM_NOTIFICATION_SERVICE_CLAIM = "https://purl.imsglobal.org/spec/lti/claim/platformnotificationservice".freeze
|
35
|
+
PLATFORM_NOTIFICATION_SERVICE_VERSIONS = ["1.0".freeze].freeze
|
36
|
+
NOTICE_TYPE_CLAIM = "https://purl.imsglobal.org/spec/lti/claim/notice_type".freeze
|
37
|
+
PLATFORM_NOTIFICATION_CONTEXT_COPY_NOTICE = "LtiContextCopyNotice".freeze
|
38
|
+
PLATFORM_NOTIFICATION_CONTEXT_COPY_ORIGINS_CLAIM = "https://purl.imsglobal.org/spec/lti/claim/origin_contexts".freeze
|
39
|
+
|
34
40
|
CALIPER_CLAIM = "https://purl.imsglobal.org/spec/lti-ces/claim/caliper-endpoint-service".freeze
|
35
41
|
|
36
42
|
TOOL_LAUNCH_CALIPER_CONTEXT = "http://purl.imsglobal.org/ctx/caliper/v1p1/ToolLaunchProfile-extension".freeze
|
@@ -43,6 +49,7 @@ module AtomicLti
|
|
43
49
|
AGS_SCOPE_SCORE = "https://purl.imsglobal.org/spec/lti-ags/scope/score".freeze
|
44
50
|
NAMES_AND_ROLES_SCOPE = "https://purl.imsglobal.org/spec/lti-nrps/scope/contextmembership.readonly".freeze
|
45
51
|
CALIPER_SCOPE = "https://purl.imsglobal.org/spec/lti-ces/v1p0/scope/send".freeze
|
52
|
+
PNS_SCOPE_NOTICEHANDLERS = "https://purl.imsglobal.org/spec/lti/scope/noticehandlers".freeze
|
46
53
|
|
47
54
|
STUDENT_SCOPE = "http://purl.imsglobal.org/vocab/lis/v2/institution/person#Student".freeze
|
48
55
|
INSTRUCTOR_SCOPE = "http://purl.imsglobal.org/vocab/lis/v2/institution/person#Instructor".freeze
|
@@ -14,6 +14,8 @@ module AtomicLti
|
|
14
14
|
class NamesAndRolesError < AtomicLtiException
|
15
15
|
end
|
16
16
|
|
17
|
+
class PlatformNotificationsError < AtomicLtiException; end
|
18
|
+
|
17
19
|
class ScoreError < AtomicLtiException
|
18
20
|
end
|
19
21
|
|
@@ -98,5 +100,7 @@ module AtomicLti
|
|
98
100
|
|
99
101
|
class PaginationLimitExceeded < AtomicLtiException
|
100
102
|
end
|
103
|
+
|
104
|
+
class InvalidPlatformNotification < AtomicLtiException; end
|
101
105
|
end
|
102
106
|
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
module AtomicLti
|
2
|
+
module Services
|
3
|
+
class PlatformNotifications < AtomicLti::Services::Base
|
4
|
+
def scopes
|
5
|
+
[AtomicLti::Definitions::PNS_SCOPE_NOTICEHANDLERS]
|
6
|
+
end
|
7
|
+
|
8
|
+
def endpoint
|
9
|
+
url = @id_token_decoded.dig(AtomicLti::Definitions::PLATFORM_NOTIFICATION_SERVICE_CLAIM, "platform_notification_service_url")
|
10
|
+
raise AtomicLti::Exceptions::PlatformNotificationsError, "Unable to access platform notifications" if url.blank?
|
11
|
+
|
12
|
+
url
|
13
|
+
end
|
14
|
+
|
15
|
+
def url_for(query = nil)
|
16
|
+
url = endpoint.dup
|
17
|
+
url << "?#{query}" if query.present?
|
18
|
+
url
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.enabled?(id_token_decoded)
|
22
|
+
return false unless id_token_decoded&.dig(AtomicLti::Definitions::PLATFORM_NOTIFICATION_SERVICE_CLAIM)
|
23
|
+
|
24
|
+
(AtomicLti::Definitions::PLATFORM_NOTIFICATION_SERVICE_VERSIONS &
|
25
|
+
(id_token_decoded.dig(AtomicLti::Definitions::PLATFORM_NOTIFICATION_SERVICE_CLAIM, "service_versions") || [])).present?
|
26
|
+
end
|
27
|
+
|
28
|
+
def valid?
|
29
|
+
self.class.enabled?(@id_token_decoded)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Get platform notifications
|
33
|
+
def get(query: {})
|
34
|
+
uri = Addressable::URI.parse(endpoint)
|
35
|
+
uri.query_values = (uri.query_values || {}).merge(query)
|
36
|
+
url = uri.to_str
|
37
|
+
|
38
|
+
response, = service_get(url, headers:)
|
39
|
+
response.parsed_response
|
40
|
+
end
|
41
|
+
|
42
|
+
def update(notice_type, handler)
|
43
|
+
content_type = { "Content-Type" => "application/json" }
|
44
|
+
payload = { notice_type:, handler: }
|
45
|
+
response, = service_put(endpoint, body: JSON.dump(payload), headers: headers(content_type))
|
46
|
+
response
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.validate_notification(notification)
|
50
|
+
decoded_token = AtomicLti::Authorization.validate_token(notification)
|
51
|
+
if decoded_token.blank?
|
52
|
+
raise AtomicLti::Exceptions::InvalidPlatformNotification
|
53
|
+
end
|
54
|
+
|
55
|
+
errors = []
|
56
|
+
|
57
|
+
if decoded_token["iss"].blank?
|
58
|
+
errors.push("LTI token is missing required field iss")
|
59
|
+
end
|
60
|
+
|
61
|
+
if decoded_token["aud"].blank?
|
62
|
+
errors.push("LTI token is missing required field aud")
|
63
|
+
end
|
64
|
+
|
65
|
+
if decoded_token["aud"].is_a?(Array) && decoded_token["aud"].length > 1
|
66
|
+
# OpenID Connect spec specifies the AZP should exist and be an AUD
|
67
|
+
if decoded_token["azp"].blank?
|
68
|
+
errors.push("LTI token has multiple aud and is missing required field azp")
|
69
|
+
elsif decoded_token["aud"].exclude?(decoded_token["azp"])
|
70
|
+
errors.push("LTI token azp is not one of the aud's")
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
if decoded_token[AtomicLti::Definitions::DEPLOYMENT_ID].blank?
|
75
|
+
errors.push(
|
76
|
+
"LTI token is missing required field #{AtomicLti::Definitions::DEPLOYMENT_ID}",
|
77
|
+
)
|
78
|
+
end
|
79
|
+
|
80
|
+
if decoded_token[AtomicLti::Definitions::NOTICE_TYPE_CLAIM].blank?
|
81
|
+
errors.push(
|
82
|
+
"LTI token is missing required claim #{AtomicLti::Definitions::NOTICE_TYPE_CLAIM}",
|
83
|
+
)
|
84
|
+
end
|
85
|
+
|
86
|
+
if errors.present?
|
87
|
+
raise Exceptions::InvalidPlatformNotification.new(errors.join(" "))
|
88
|
+
end
|
89
|
+
|
90
|
+
if decoded_token[AtomicLti::Definitions::LTI_VERSION].blank?
|
91
|
+
raise AtomicLti::Exceptions::NoLTIVersion
|
92
|
+
end
|
93
|
+
|
94
|
+
raise AtomicLti::Exceptions::InvalidLTIVersion unless AtomicLti::Lti.valid_version?(decoded_token)
|
95
|
+
|
96
|
+
decoded_token
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
data/lib/atomic_lti/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: atomic_lti
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.10.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Matt Petro
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2024-07-
|
13
|
+
date: 2024-07-05 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: pg
|
@@ -77,6 +77,7 @@ files:
|
|
77
77
|
- app/lib/atomic_lti/services/base.rb
|
78
78
|
- app/lib/atomic_lti/services/line_items.rb
|
79
79
|
- app/lib/atomic_lti/services/names_and_roles.rb
|
80
|
+
- app/lib/atomic_lti/services/platform_notifications.rb
|
80
81
|
- app/lib/atomic_lti/services/results.rb
|
81
82
|
- app/lib/atomic_lti/services/score.rb
|
82
83
|
- app/lib/atomic_lti/services/score_canvas.rb
|