atomic_lti/
deep_linking.rs1use self::html_fragment::HtmlFragment;
2use self::image::Image;
3use self::link::Link;
4use self::lti_resource_link::LTIResourceLink;
5use crate::deep_linking::file::File;
6use crate::errors::SecureError;
7use crate::jwt;
8use crate::{
9 lti_definitions::{DEEP_LINKING_VERSION, LTI_DEEP_LINKING_RESPONSE},
10 secure::generate_secure_string,
11};
12use chrono::{Duration, Utc};
13use openssl::rsa::Rsa;
14use serde::{Deserialize, Serialize};
15use serde_with::skip_serializing_none;
16
17pub mod file;
18pub mod html_fragment;
19pub mod image;
20pub mod link;
21pub mod lti_resource_link;
22pub mod shared;
23
24#[skip_serializing_none]
25#[derive(Debug, Deserialize, Serialize, Clone)]
26#[serde(tag = "type")]
27pub enum ContentItem {
28 #[serde(rename = "file")]
29 #[serde(alias = "file", alias = "File", alias = "FILE")]
30 File(File),
31 #[serde(rename = "html")]
32 #[serde(alias = "html", alias = "Html", alias = "HTML")]
33 HtmlFragment(HtmlFragment),
34 #[serde(rename = "image")]
35 #[serde(alias = "image", alias = "Image")]
36 Image(Image),
37 #[serde(rename = "link")]
38 #[serde(alias = "link", alias = "Link")]
39 Link(Link),
40 #[serde(rename = "ltiResourceLink")]
41 #[serde(
42 alias = "ltiResourceLink",
43 alias = "ltiresourcelink",
44 alias = "LtiResourceLink"
45 )]
46 LTIResourceLink(LTIResourceLink),
47}
48
49#[skip_serializing_none]
50#[derive(Debug, Deserialize, Serialize, Clone)]
51pub struct DeepLinkPayload {
52 pub iss: String, pub aud: String, pub azp: String, pub exp: i64,
56 pub iat: i64,
57 pub nonce: String,
58 #[serde(rename = "https://purl.imsglobal.org/spec/lti/claim/message_type")]
59 pub message_type: String,
60 #[serde(rename = "https://purl.imsglobal.org/spec/lti/claim/version")]
61 pub version: String,
62 #[serde(rename = "https://purl.imsglobal.org/spec/lti/claim/deployment_id")]
63 pub deployment_id: String,
64 #[serde(rename = "https://purl.imsglobal.org/spec/lti-dl/claim/content_items")]
65 pub content_items: Vec<ContentItem>,
66 #[serde(rename = "https://purl.imsglobal.org/spec/lti-dl/claim/data")]
67 pub data: Option<String>,
68}
69
70impl DeepLinkPayload {
71 pub fn new(
81 client_id: &str,
82 iss: &str,
83 deployment_id: &str,
84 content_items: Vec<ContentItem>,
85 deep_link_claim_data: Option<String>,
86 ) -> Self {
87 let now = Utc::now().timestamp();
88 let nonce: String = generate_secure_string(32);
89
90 DeepLinkPayload {
91 iss: client_id.to_string(),
92 aud: iss.to_string(),
93 azp: client_id.to_string(),
94 exp: (Utc::now() + Duration::minutes(5)).timestamp(),
95 iat: now,
96 nonce,
97 message_type: LTI_DEEP_LINKING_RESPONSE.to_string(),
98 version: DEEP_LINKING_VERSION.to_string(),
99 deployment_id: deployment_id.to_string(),
100 content_items,
101 data: deep_link_claim_data,
102 }
103 }
104}
105pub struct DeepLinking;
106
107impl DeepLinking {
108 pub fn create_deep_link_jwt(
109 client_id: &str,
110 iss: &str,
111 deployment_id: &str,
112 content_items: &[ContentItem],
113 deep_link_claim_data: Option<String>,
114 kid: &str,
115 rsa_key_pair: Rsa<openssl::pkey::Private>,
116 ) -> Result<String, SecureError> {
117 let payload = DeepLinkPayload::new(
118 client_id,
119 iss,
120 deployment_id,
121 content_items.to_owned(),
122 deep_link_claim_data,
123 );
124
125 jwt::encode(&payload, kid, rsa_key_pair)
127 }
128}
129
130#[cfg(test)]
131mod tests {
132 use super::*;
133
134 #[test]
135 fn test_new_deep_link_payload() {
136 let client_id = "client_id";
137 let iss = "iss";
138 let deployment_id = "deployment_id";
139 let link = Link {
140 type_: "link".to_string(),
141 url: "https://example.com".to_string(),
142 title: Some("Example".to_string()),
143 text: Some("Example".to_string()),
144 icon: None,
145 thumbnail: None,
146 embed: None,
147 window: None,
148 iframe: None,
149 };
150 let content_items = vec![ContentItem::Link(link)];
151 let deep_link_claim_data = Some("data".to_string());
152
153 let payload = DeepLinkPayload::new(
154 client_id,
155 iss,
156 deployment_id,
157 content_items,
158 deep_link_claim_data.clone(),
159 );
160
161 assert_eq!(payload.iss, client_id);
162 assert_eq!(payload.aud, iss);
163 assert_eq!(payload.azp, client_id);
164 assert_eq!(payload.data, deep_link_claim_data);
165 }
166}