ocm-types 0.2.1

Types required to implement the OpenCloudMesh filesharing protocol
Documentation
// SPDX-FileCopyrightText: 2026 Matthias Kraus <info@opengeomesh.org>
//
// SPDX-License-Identifier: LGPL-3.0-or-later

//! Protocol Properties for access protocols specified within OpenCloudMesh
//! The Protocol Properties are used in [crate::shares::NewShare] to inform the Receiving Server
//! about how to access a shared Resource.

mod ssh;
mod webapp;
mod webdav;
pub use ssh::*;
pub use webapp::*;
pub use webdav::*;

use std::collections::HashMap;

use serde::{Deserialize, Serialize};
use serde_json::{Map, Value};

/// JSON object with specific options for each protocol.
///
/// The supported protocols are:
/// - `webdav`, to access the data
/// - `webapp`, to access remote web applications
/// - `ssh`, to access the data via SFTP/SCP
///
/// Other custom protocols might be added in the future.
///
/// # Single Protocol Legacy
/// ```
/// use ocm_types::share::Protocol;
/// use serde_json::Map;
/// use serde_json::Value;
/// use serde_json::json;
///
/// #[allow(deprecated)]
/// let single_protocol_legacy = Protocol{
///     name: "webdav".to_string(),
///     options: Some(Map::from_iter(vec![
///         ("sharedSecret".to_string(), Value::String("hfiuhworzwnur98d3wjiwhr".to_string())),
///         ("permissions".to_string(), Value::String("some permissions scheme".to_string())),
///     ].into_iter())),
///     ..Default::default()
/// };
/// let json: Value = serde_json::from_str(r#"{
///     "name": "webdav",
///     "options": {
///         "sharedSecret": "hfiuhworzwnur98d3wjiwhr",
///         "permissions": "some permissions scheme"
///     }
/// }"#).unwrap();
/// assert_eq!(json!(single_protocol_legacy), json);
/// ```
///
/// # Single Protocol New
/// ```
/// use ocm_types::share::Protocol;
/// use ocm_types::share::WebDavProperties;
/// use ocm_types::share::WebDavPermissions;
/// use ocm_types::share::AccessType;
/// use std::collections::HashMap;
/// use serde_json::Value;
/// use serde_json::json;
/// use serde::de::Deserialize;
///
/// let single_protocol_new = Protocol{
///     name: "multi".to_string(),
///     webdav: Some(WebDavProperties{
///         access_types: vec![AccessType::Remote],
///         uri: "7c084226-d9a1-11e6-bf26-cec0c932ce01".to_string(),
///         shared_secret: Some("hfiuhworzwnur98d3wjiwhr".to_string()),
///         refresh_token: None,
///         permissions: vec![
///             WebDavPermissions::Read,
///             WebDavPermissions::Write,
///         ],
///         requirements: vec![]
///     }),
///     ..Default::default()
/// };
/// let json: Value = serde_json::from_str(r#"{
///     "name": "multi",
///     "webdav": {
///         "accessTypes": ["remote"],
///         "uri": "7c084226-d9a1-11e6-bf26-cec0c932ce01",
///         "sharedSecret": "hfiuhworzwnur98d3wjiwhr",
///         "permissions": ["read", "write"]
///     }
/// }"#).unwrap();
/// assert_eq!(json!(single_protocol_new), json);
/// ```
///
/// # Multi Protocol
/// ```
/// use ocm_types::share::Protocol;
/// use ocm_types::share::WebDavProperties;
/// use ocm_types::share::WebDavPermissions;
/// use ocm_types::share::WebDavRequirements;
/// use ocm_types::share::WebAppProperties;
/// use ocm_types::share::WebAppViewMode;
/// use ocm_types::share::SshProperties;
/// use ocm_types::share::AccessType;
/// use std::collections::HashMap;
/// use serde_json::Value;
/// use serde_json::json;
///
/// let single_protocol_new = Protocol{
///     name: "multi".to_string(),
///     webdav: Some(WebDavProperties{
///         access_types: vec![AccessType::Remote],
///         uri: "7c084226-d9a1-11e6-bf26-cec0c932ce01".to_string(),
///         shared_secret: Some("hfiuhworzwnur98d3wjiwhr".to_string()),
///         refresh_token: None,
///         permissions: vec![
///             WebDavPermissions::Read,
///             WebDavPermissions::Write
///         ],
///         requirements: vec![
///             WebDavRequirements::MustUseMfa
///         ]
///     }),
///     webapp: Some(WebAppProperties{
///         uri: "7c084226-d9a1-11e6-bf26-cec0c932ce01".to_string(),
///         shared_secret: Some("hfiuhworzwnur98d3wjiwhr".to_string()),
///         view_mode: WebAppViewMode::Read
///     }),
///     ssh: Some(SshProperties{
///         access_types: vec![AccessType::DataTx],
///         uri: "extuser@cloud.example.org:/7c084226-d9a1-11e6-bf26-cec0c932ce01".to_string()
///     }),
///     additional_protocols: HashMap::from_iter(vec![
///         (
///             "datatx".to_string(), 
///             json!({
///                 "srcUri": "7c084226-d9a1-11e6-bf26-cec0c932ce01",
///                 "sharedSecret": "hfiuhworzwnur98d3wjiwhr",
///                 "size": 100000
///             })
///         )
///     ].into_iter()),
///     ..Default::default()
/// };
/// let json: Value = serde_json::from_str(r#"{
///     "name": "multi",
///     "webdav": {
///         "accessTypes": ["remote"],
///         "uri": "7c084226-d9a1-11e6-bf26-cec0c932ce01",
///         "sharedSecret": "hfiuhworzwnur98d3wjiwhr",
///         "permissions": ["read", "write"],
///         "requirements": ["must-use-mfa"]
///     },
///     "webapp": {
///       "uri": "7c084226-d9a1-11e6-bf26-cec0c932ce01",
///       "sharedSecret": "hfiuhworzwnur98d3wjiwhr",
///       "viewMode": "read"
///     },
///     "datatx": {
///      "srcUri": "7c084226-d9a1-11e6-bf26-cec0c932ce01",
///      "sharedSecret": "hfiuhworzwnur98d3wjiwhr",
///      "size": 100000
///     },
///     "ssh": {
///         "accessTypes": ["datatx"],
///         "uri": "extuser@cloud.example.org:/7c084226-d9a1-11e6-bf26-cec0c932ce01"
///     }
/// }"#).unwrap();
/// assert_eq!(json!(single_protocol_new), json);
/// ```
///
/// # WebDAV with refreshToken
/// ```
/// # use ocm_types::share::Protocol;
/// # use ocm_types::share::AccessType;
/// # use ocm_types::share::WebDavProperties;
/// # use ocm_types::share::WebDavPermissions;
/// # use ocm_types::share::WebDavRequirements;
/// # use ocm_types::share::WebAppProperties;
/// # use ocm_types::share::WebAppViewMode;
/// # use std::collections::HashMap;
/// # use serde_json::Value;
/// # use serde_json::json;
///
/// let webdav_refresh_token = Protocol{
///     name: "multi".to_string(),
///     webdav: Some(WebDavProperties{
///         access_types: vec![AccessType::Remote],
///         uri: "7c084226-d9a1-11e6-bf26-cec0c932ce01".to_string(),
///         shared_secret: None,
///         refresh_token: Some("hfiuhworzwnur98d3wjiwhr".to_string()),
///         permissions: vec![
///             WebDavPermissions::Read,
///             WebDavPermissions::Write
///         ],
///         requirements: vec![
///             WebDavRequirements::MustUseMfa,
///             WebDavRequirements::MustExchangeToken
///         ]
///     }),
///     webapp: Some(WebAppProperties{
///         uri: "7c084226-d9a1-11e6-bf26-cec0c932ce01".to_string(),
///         shared_secret: Some("hfiuhworzwnur98d3wjiwhr".to_string()),
///         view_mode: WebAppViewMode::Read
///     }),
///     additional_protocols: HashMap::from_iter(vec![
///         (
///             "datatx".to_string(), 
///             json!({
///                 "srcUri": "7c084226-d9a1-11e6-bf26-cec0c932ce01",
///                 "sharedSecret": "hfiuhworzwnur98d3wjiwhr",
///                 "size": 100000
///             })
///         )
///     ].into_iter()),
///     ..Default::default()
/// };
/// let json: Value = serde_json::from_str(r#"{
///     "name": "multi",
///     "webdav": {
///         "accessTypes": ["remote"],
///         "uri": "7c084226-d9a1-11e6-bf26-cec0c932ce01",
///         "refreshToken": "hfiuhworzwnur98d3wjiwhr",
///         "permissions": ["read", "write"],
///         "requirements": ["must-use-mfa", "must-exchange-token"]
///     },
///     "webapp": {
///       "uri": "7c084226-d9a1-11e6-bf26-cec0c932ce01",
///       "sharedSecret": "hfiuhworzwnur98d3wjiwhr",
///       "viewMode": "read"
///     },
///     "datatx": {
///      "srcUri": "7c084226-d9a1-11e6-bf26-cec0c932ce01",
///      "sharedSecret": "hfiuhworzwnur98d3wjiwhr",
///      "size": 100000
///     }
/// }"#).unwrap();
/// assert_eq!(json!(webdav_refresh_token), json);
/// ```
// example:
//   multipleProtocols:
//     name: multi
//     webapp:
//       uri: 7c084226-d9a1-11e6-bf26-cec0c932ce01
//       sharedSecret: hfiuhworzwnur98d3wjiwhr
//       viewMode: read
//     datatx:
//       srcUri: 7c084226-d9a1-11e6-bf26-cec0c932ce01
//       sharedSecret: hfiuhworzwnur98d3wjiwhr
//       size: 100000
#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Protocol {
    /// The name of the protocol. Default: `multi`.
    /// If `multi` is given, one or more protocol endpoints are expected
    /// to be defined according to the optional properties specified below.
    /// Otherwise, at least `webdav` is expected to be supported, and
    /// its options MAY be given in the opaque `options` payload for
    /// compatibility with v1.0 implementations (see examples). Note
    /// though that this format is deprecated.
    /// Warning: client implementers should be aware that v1.1 servers
    /// MAY support both `webdav` and `multi`, but v1.0 servers MAY
    /// only support `webdav`.
    /// This field may be removed in a future major version of the spec.
    pub name: String,
    /// This property is now deprecated. Implementations are
    /// encouraged to transition to the new optional properties
    /// defined below, such that this field may be removed in a future major
    /// version of the spec.
    #[deprecated]
    #[serde(skip_serializing_if = "Option::is_none", default)]
    pub options: Option<Map<String, Value>>,
    #[serde(skip_serializing_if = "Option::is_none", default)]
    pub webdav: Option<WebDavProperties>,
    #[serde(skip_serializing_if = "Option::is_none", default)]
    pub webapp: Option<WebAppProperties>,
    #[serde(skip_serializing_if = "Option::is_none", default)]
    pub ssh: Option<SshProperties>,
    /// Any optional additional protocols supported for this resource
    /// MAY
    /// be provided here, along with their custom payload. Appropriate
    /// capabilities MUST be advertised in order for a sender to ensure
    /// the recipient can parse such customized payloads.
    #[serde(skip_serializing_if = "HashMap::is_empty", default)]
    #[serde(flatten)]
    pub additional_protocols: HashMap<String, Value>,
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum AccessType {
    /// signals the recipient that the resource is available
    /// for remote access and interactive browsing.
    Remote,
    /// signals the recipient to transfer the resource
    /// from the given URI. The recipient MAY delegate a third-party
    /// service to execute the data transfer on their behalf.
    DataTx,
}

fn default_access_types() -> Vec<AccessType> {
    vec![AccessType::Remote]
}