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}