ocm_types/share.rs
1use std::collections::HashMap;
2
3use serde::{Deserialize, Serialize};
4use serde_json::{json, Map, Value};
5
6use crate::common::{OcmAddress, ShareType};
7
8#[derive(Debug, PartialEq, Eq, Default, Clone, Serialize, Deserialize)]
9#[serde(rename_all = "camelCase")]
10pub struct NewShare {
11 /// Consumer specific identifier of the user, group or federation the provider
12 /// wants to share the resource with. This is known in advance.
13 /// Please note that the consumer service endpoint is known in advance
14 /// as well, so this is no part of the request body.
15 /// example: 51dc30ddc473d43a6011e9ebba6ca770@geant.org
16 pub share_with: OcmAddress,
17 /// Name of the resource (file or folder).
18 /// example: resource.txt
19 pub name: String,
20 /// Optional description of the resource (file or folder).
21 #[serde(skip_serializing_if = "Option::is_none", default)]
22 pub description: Option<String>,
23 /// Identifier to identify the shared resource at the provider side.
24 /// This is unique per provider such that if the same resource is shared twice,
25 /// this providerId will not be repeated.
26 ///
27 /// example: 7c084226-d9a1-11e6-bf26-cec0c932ce01
28 pub provider_id: String,
29 /// Provider specific identifier of the user who owns the resource.
30 ///
31 /// example: 6358b71804dfa8ab069cf05ed1b0ed2a@apiwise.nl
32 pub owner: OcmAddress,
33 /// Provider specific identifier of the user that wants to share the
34 /// resource. Please note that the requesting provider is being
35 /// identified on a higher level, so the former `remote` property
36 /// is not part of the request body.
37 ///
38 /// example: 527bd5b5d689e2c32ae974c6229ff785@apiwise.nl
39 pub sender: OcmAddress,
40 /// Display name of the owner of the resource
41 /// example: Dimitri
42 #[serde(skip_serializing_if = "Option::is_none", default)]
43 pub owner_display_name: Option<String>,
44 /// Display name of the user that wants to share the resource
45 /// example: John Doe
46 #[serde(skip_serializing_if = "Option::is_none", default)]
47 pub sender_display_name: Option<String>,
48 /// Recipient share type
49 pub share_type: ShareType,
50 /// Resource type (file, calendar, contact, ...)
51 /// example: file
52 pub resource_type: String,
53 /// The expiration time for the share, in seconds of UTC time since
54 /// Unix epoch. If omitted, it is assumed that the share does not expire.
55 #[serde(skip_serializing_if = "Option::is_none", default)]
56 pub expiration: Option<i64>,
57 /// A nonce to be exchanged for a (potentially short-lived) bearer token
58 /// at the Sending Server's `/token` endpoint.
59 #[serde(skip_serializing_if = "Option::is_none", default)]
60 pub code: Option<String>,
61 pub protocol: Protocol,
62}
63
64/// The Sending Server
65/// * holds the Resource ("file server" or "Entreprise File Sync and Share (EFSS) server" role), provides access to it (by exposing at least one "API"),
66/// * takes the decision to create the Share based on user interface gestures from the Sending Party (the "Authorization Server" role in OAuth)
67/// * takes the decision about authorizing attempts to access the Resource (the "Resource Server" role in OAuth)
68/// * sends out Share Creation Notifications when appropriate
69#[derive(Debug, Clone, PartialEq, Eq, Hash)]
70pub struct SendingServer(String);
71
72impl NewShare {
73 /// Get the Sending Server from the sender of the share.
74 pub fn sending_server(&self) ->SendingServer {
75 SendingServer(self.owner.get_server_url().into())
76 }
77}
78
79impl<T: Into<String>> From<T> for SendingServer {
80 fn from(value: T) -> Self {
81 // FIXME make sure this is a fqdn
82 Self(value.into())
83 }
84}
85impl AsRef<str> for SendingServer {
86 fn as_ref(&self) -> &str {
87 &self.0
88 }
89}
90
91/// JSON object with specific options for each protocol.
92///
93/// The supported protocols are:
94/// - `webdav`, to access the data
95/// - `webapp`, to access remote web applications
96/// - `datatx`, to transfer the data to the remote endpoint
97///
98/// Other custom protocols might be added in the future.
99///
100/// # Single Protocol Legacy
101/// ```
102/// use ocm_types::share::Protocol;
103/// use serde_json::Map;
104/// use serde_json::Value;
105/// use serde_json::json;
106///
107/// #[allow(deprecated)]
108/// let single_protocol_legacy = Protocol{
109/// name: "webdav".to_string(),
110/// options: Some(Map::from_iter(vec![
111/// ("sharedSecret".to_string(), Value::String("hfiuhworzwnur98d3wjiwhr".to_string())),
112/// ("permissions".to_string(), Value::String("some permissions scheme".to_string())),
113/// ].into_iter())),
114/// ..Default::default()
115/// };
116/// let json: Value = serde_json::from_str(r#"{
117/// "name": "webdav",
118/// "options": {
119/// "sharedSecret": "hfiuhworzwnur98d3wjiwhr",
120/// "permissions": "some permissions scheme"
121/// }
122/// }"#).unwrap();
123/// assert_eq!(json!(single_protocol_legacy), json);
124/// ```
125///
126/// # Single Protocol New
127/// ```
128/// use ocm_types::share::Protocol;
129/// use ocm_types::share::WebDavProperties;
130/// use ocm_types::share::WebDavPermissions;
131/// use std::collections::HashMap;
132/// use serde_json::Value;
133/// use serde_json::json;
134///
135/// let single_protocol_new = Protocol{
136/// name: "multi".to_string(),
137/// webdav: Some(WebDavProperties{
138/// uri: "7c084226-d9a1-11e6-bf26-cec0c932ce01".to_string(),
139/// shared_secret: Some("hfiuhworzwnur98d3wjiwhr".to_string()),
140/// permissions: vec![
141/// WebDavPermissions::Read,
142/// WebDavPermissions::Write,
143/// ],
144/// requirements: vec![]
145/// }),
146/// ..Default::default()
147/// };
148/// let json: Value = serde_json::from_str(r#"{
149/// "name": "multi",
150/// "webdav": {
151/// "uri": "7c084226-d9a1-11e6-bf26-cec0c932ce01",
152/// "sharedSecret": "hfiuhworzwnur98d3wjiwhr",
153/// "permissions": ["read", "write"]
154/// }
155/// }"#).unwrap();
156/// assert_eq!(json!(single_protocol_new), json);
157/// ```
158///
159/// # Multi Protocol
160/// ```
161/// use ocm_types::share::Protocol;
162/// use ocm_types::share::WebDavProperties;
163/// use ocm_types::share::WebDavPermissions;
164/// use ocm_types::share::WebDavRequirements;
165/// use ocm_types::share::WebAppProperties;
166/// use ocm_types::share::WebAppViewMode;
167/// use ocm_types::share::DataTxProperties;
168/// use std::collections::HashMap;
169/// use serde_json::Value;
170/// use serde_json::json;
171///
172/// let single_protocol_new = Protocol{
173/// name: "multi".to_string(),
174/// webdav: Some(WebDavProperties{
175/// uri: "7c084226-d9a1-11e6-bf26-cec0c932ce01".to_string(),
176/// shared_secret: Some("hfiuhworzwnur98d3wjiwhr".to_string()),
177/// permissions: vec![
178/// WebDavPermissions::Read,
179/// WebDavPermissions::Write
180/// ],
181/// requirements: vec![
182/// WebDavRequirements::MfaEnforced
183/// ]
184/// }),
185/// webapp: Some(WebAppProperties{
186/// uri: "7c084226-d9a1-11e6-bf26-cec0c932ce01".to_string(),
187/// shared_secret: Some("hfiuhworzwnur98d3wjiwhr".to_string()),
188/// view_mode: WebAppViewMode::Read
189/// }),
190/// datatx: Some(DataTxProperties{
191/// src_uri: "7c084226-d9a1-11e6-bf26-cec0c932ce01".to_string(),
192/// shared_secret: "hfiuhworzwnur98d3wjiwhr".to_string(),
193/// size: Some(100000)
194/// }),
195/// ..Default::default()
196/// };
197/// let json: Value = serde_json::from_str(r#"{
198/// "name": "multi",
199/// "webdav": {
200/// "uri": "7c084226-d9a1-11e6-bf26-cec0c932ce01",
201/// "sharedSecret": "hfiuhworzwnur98d3wjiwhr",
202/// "permissions": ["read", "write"],
203/// "requirements": ["mfa-enforced"]
204/// },
205/// "webapp": {
206/// "uri": "7c084226-d9a1-11e6-bf26-cec0c932ce01",
207/// "sharedSecret": "hfiuhworzwnur98d3wjiwhr",
208/// "viewMode": "read"
209/// },
210/// "datatx": {
211/// "srcUri": "7c084226-d9a1-11e6-bf26-cec0c932ce01",
212/// "sharedSecret": "hfiuhworzwnur98d3wjiwhr",
213/// "size": 100000
214/// }
215/// }"#).unwrap();
216/// assert_eq!(json!(single_protocol_new), json);
217/// ```
218// example:
219// multipleProtocols:
220// name: multi
221// webapp:
222// uri: 7c084226-d9a1-11e6-bf26-cec0c932ce01
223// sharedSecret: hfiuhworzwnur98d3wjiwhr
224// viewMode: read
225// datatx:
226// srcUri: 7c084226-d9a1-11e6-bf26-cec0c932ce01
227// sharedSecret: hfiuhworzwnur98d3wjiwhr
228// size: 100000
229#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize, Deserialize)]
230#[serde(rename_all = "camelCase")]
231pub struct Protocol {
232 /// The name of the protocol. Default: `multi`.
233 /// If `multi` is given, one or more protocol endpoints are expected
234 /// to be defined according to the optional properties specified below.
235 /// Otherwise, at least `webdav` is expected to be supported, and
236 /// its options MAY be given in the opaque `options` payload for
237 /// compatibility with v1.0 implementations (see examples). Note
238 /// though that this format is deprecated.
239 /// Warning: client implementers should be aware that v1.1 servers
240 /// MAY support both `webdav` and `multi`, but v1.0 servers MAY
241 /// only support `webdav`.
242 /// This field may be removed in a future major version of the spec.
243 pub name: String,
244 /// This property is now deprecated. Implementations are
245 /// encouraged to transition to the new optional properties
246 /// defined below, such that this field may be removed in a future major
247 /// version of the spec.
248 #[deprecated]
249 #[serde(skip_serializing_if = "Option::is_none", default)]
250 pub options: Option<Map<String, Value>>,
251 #[serde(skip_serializing_if = "Option::is_none", default)]
252 pub webdav: Option<WebDavProperties>,
253 #[serde(skip_serializing_if = "Option::is_none", default)]
254 pub webapp: Option<WebAppProperties>,
255 #[serde(skip_serializing_if = "Option::is_none", default)]
256 pub datatx: Option<DataTxProperties>,
257 /// Any optional additional protocols supported for this resource
258 /// MAY
259 /// be provided here, along with their custom payload. Appropriate
260 /// capabilities MUST be advertised in order for a sender to ensure
261 /// the recipient can parse such customized payloads.
262 #[serde(skip_serializing_if = "HashMap::is_empty", default)]
263 #[serde(flatten)]
264 pub additional_protocols: HashMap<String, Value>,
265}
266
267#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
268#[serde(rename_all = "camelCase")]
269pub struct WebDavProperties {
270 /// An URI to access the remote resource. The URI SHOULD be
271 /// relative,
272 /// such as a key or a UUID, in which case the prefix exposed by the
273 /// `/.well-known/ocm` endpoint MUST be used to access the resource,
274 /// or it MAY be absolute, including a hostname. The latter is NOT
275 /// recommended because of security concerns.
276 /// In all cases, for a `folder` resource, the composed URI acts
277 /// as the root path, such that other files located within SHOULD
278 /// be accessible by appending their relative path to that URI.
279 pub uri: String,
280 /// An optional secret to be used to access the resource, such
281 /// as
282 /// a bearer token. If a `code` is provided, it SHOULD be used
283 /// instead via the code flow interaction, and the `sharedSecret`
284 /// SHOULD be omitted. To prevent leaking it in logs it MUST NOT
285 /// appear in any URI.
286 #[serde(skip_serializing_if = "Option::is_none", default)]
287 pub shared_secret: Option<String>,
288 /// The permissions granted to the sharee.
289 #[serde(skip_serializing_if = "Vec::is_empty", default)]
290 pub permissions: Vec<WebDavPermissions>,
291 /// A list of requirements that the recipient provider MUST
292 /// fulfill
293 /// to access the resource. Requirements are optional, but if it is
294 /// present it MUST NOT be empty. A recipient provider MUST reject
295 /// a share whose requirements it does not understand.
296 #[serde(skip_serializing_if = "Vec::is_empty", default)]
297 pub requirements: Vec<WebDavRequirements>,
298}
299
300#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
301#[serde(rename_all = "kebab-case")]
302pub enum WebDavRequirements {
303 /// `mfa-enforced` requires the user accessing the resource to be
304 /// MFA-authenticated. This requirement MAY be used if the
305 /// recipient provider exposes the `enforce-mfa` capability.
306 MfaEnforced,
307 /// `use-code` requires the recipient to exchange the given
308 /// `code` via a signed HTTPS request to `/token` at the Sending
309 /// Server, in order to get a short-lived token to be used for
310 /// subsequent access. This requirement MAY be used if the
311 /// recipient provider exposes the `receive-code` capability.
312 UseCode,
313}
314
315#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
316#[serde(rename_all = "kebab-case")]
317pub enum WebDavPermissions {
318 /// allows read-only access including download of a copy.
319 Read,
320 /// allows create, update, and delete rights on the resource.
321 Write,
322 /// allows re-share rights on the resource.
323 Share,
324}
325
326impl TryFrom<WebDavProperties> for Map<String, Value> {
327 // FIXME use proper error
328 type Error = String;
329
330 fn try_from(value: WebDavProperties) -> Result<Self, Self::Error> {
331 let json = json!(value);
332 serde_json::from_value(json).map_err(|e| e.to_string())
333 }
334}
335
336#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
337#[serde(rename_all = "camelCase")]
338pub struct WebAppProperties {
339 /// An URI to a client-browsable view of the remote resource,
340 /// such that
341 /// users may use a web application available at the sender site.
342 /// The URI SHOULD be relative, such as a key or a UUID, in which case
343 /// the prefix exposed by the `/.well-known/ocm` endpoint MUST be used
344 /// to access the resource, or it MAY be absolute, including a hostname.
345 /// The latter is NOT recommended because of security concerns.
346 /// In all cases, for a `folder` resource, the composed URI acts
347 /// as the root path, such that other files located within SHOULD
348 /// be accessible by appending their relative path to that URI.
349 pub uri: String,
350 /// The permissions granted to the sharee.
351 pub view_mode: WebAppViewMode,
352 /// An optional secret to be used to access the remote web
353 /// app, such as
354 /// a bearer token. To prevent leaking it in logs it MUST NOT appear
355 /// in any URI. If a `code` is provided, then the sending host MUST
356 /// accept the short-lived bearer token when serving the web app,
357 /// which can be exchanged in the code flow interaction. The exchange
358 /// MAY already have happened if the recipient accessed the underlying
359 /// resource via WebDAV, in a multi-protocol scenario. In this case,
360 /// the `sharedSecret` SHOULD be omitted.
361 #[serde(skip_serializing_if = "Option::is_none", default)]
362 pub shared_secret: Option<String>,
363}
364
365#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
366#[serde(rename_all = "kebab-case")]
367pub enum WebAppViewMode {
368 /// `read` allows read-only access including download of a copy.
369 Read,
370 /// `write` allows create, update, and delete rights on the resource.
371 Write,
372 /// `share` allows re-sharing rights on the resource.
373 Share,
374}
375
376#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize, Deserialize)]
377#[serde(rename_all = "camelCase")]
378pub struct DataTxProperties {
379 /// An optional secret to be used to access the resource, such
380 /// as
381 /// a bearer token. If a `code` is provided, it SHOULD be used
382 /// instead via the code flow interaction, and the `sharedSecret`
383 /// SHOULD be omitted. To prevent leaking it in logs it MUST NOT
384 /// appear in any URI.
385 pub shared_secret: String,
386
387 /// An URI to access the resource at the sending server. The
388 /// URI
389 /// SHOULD be relative, such as a key or a UUID, in which case the
390 /// prefix exposed by the `/.well-known/ocm` endpoint SHOULD be used
391 /// to access the resource, or it MAY be absolute, including
392 /// a hostname. The latter is NOT recommended because of security
393 /// concerns.
394 pub src_uri: String,
395 /// The size of the file to be transferred from the sending server.
396 pub size: Option<u64>,
397}
398
399/// Consumer successfully received the share. The response might contain
400/// the display name of the recipient of the share for general user
401/// experience improvement.
402#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize, Deserialize)]
403#[serde(rename_all = "camelCase")]
404pub struct ShareCreationResponse {
405 /// display name of the recipient
406 /// example: John Doe
407 pub recipient_display_name: Option<String>,
408}