ocm_types/share/protocols/webdav.rs
1// SPDX-FileCopyrightText: 2026 Matthias Kraus <info@opengeomesh.org>
2//
3// SPDX-License-Identifier: LGPL-3.0-or-later
4
5use serde::{Deserialize, Serialize};
6use serde_json::{Map, Value, json};
7
8use super::AccessType;
9use super::default_access_types;
10
11#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
12#[serde(rename_all = "camelCase")]
13pub struct WebDavProperties {
14 /// The type of access being granted to the remote resource.
15 /// If omitted, it defaults to `['remote']`.
16 /// - `remote` signals the recipient that the resource is available
17 /// for remote access and interactive browsing.
18 /// - `datatx` signals the recipient to transfer the resource
19 /// from the given URI. The recipient MAY delegate a third-party
20 /// service to execute the data transfer on their behalf.
21 #[serde(
22 skip_serializing_if = "Vec::is_empty",
23 default = "default_access_types"
24 )]
25 pub access_types: Vec<AccessType>,
26 /// An URI to access the remote resource. The URI SHOULD be
27 /// relative,
28 /// such as a key or a UUID, in which case the prefix exposed by the
29 /// `/.well-known/ocm` endpoint MUST be used to access the resource,
30 /// or it MAY be absolute, including a hostname. The latter is NOT
31 /// recommended because of security concerns.
32 /// In all cases, for a `folder` resource, the composed URI acts
33 /// as the root path, such that other files located within SHOULD
34 /// be accessible by appending their relative path to that URI.
35 pub uri: String,
36 /// An optional secret to be used to access the resource, such
37 /// as
38 /// a bearer token. If a `refreshToken` is provided, it SHOULD be used
39 /// instead via the code flow interaction, and the `sharedSecret`
40 /// SHOULD be omitted. To prevent leaking it in logs it MUST NOT
41 /// appear in any URI.
42 #[serde(skip_serializing_if = "Option::is_none", default)]
43 pub shared_secret: Option<String>,
44 /// A Token to be exchanged for a short-lived bearer token at the tokenEndPoint
45 /// of the Sending Server for access to the shared resource.
46 #[serde(skip_serializing_if = "Option::is_none", default)]
47 pub refresh_token: Option<String>,
48 /// The permissions granted to the sharee.
49 #[serde(skip_serializing_if = "Vec::is_empty", default)]
50 pub permissions: Vec<WebDavPermissions>,
51 /// A list of requirements that the recipient provider MUST
52 /// fulfill
53 /// to access the resource. Requirements are optional, but if it is
54 /// present it MUST NOT be empty. A recipient provider MUST reject
55 /// a share whose requirements it does not understand.
56 #[serde(skip_serializing_if = "Vec::is_empty", default)]
57 pub requirements: Vec<WebDavRequirements>,
58}
59
60#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
61#[serde(rename_all = "kebab-case")]
62pub enum WebDavRequirements {
63 /// `must-use-mfa` requires the user accessing the resource to be
64 /// MFA-authenticated. This requirement MAY be used if the
65 /// recipient provider exposes the `enforce-mfa` capability.
66 MustUseMfa,
67 /// `must-exchange-token` requires the recipient to exchange the given
68 /// `refreshToken` via a signed HTTPS request to tokenEndPoint at the Sending
69 /// Server, in order to get a short-lived token to be used for
70 /// subsequent access. This requirement MAY be used if the
71 /// recipient provider exposes the [`exchange-token`
72 /// capability](crate::discovery::Capability::ExchangeToken).
73 MustExchangeToken,
74}
75
76#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
77#[serde(rename_all = "kebab-case")]
78pub enum WebDavPermissions {
79 /// allows read-only access including download of a copy.
80 Read,
81 /// allows create, update, and delete rights on the resource.
82 Write,
83 /// allows re-share rights on the resource.
84 Share,
85}
86
87impl TryFrom<WebDavProperties> for Map<String, Value> {
88 // FIXME use proper error
89 type Error = String;
90
91 fn try_from(value: WebDavProperties) -> Result<Self, Self::Error> {
92 let json = json!(value);
93 serde_json::from_value(json).map_err(|e| e.to_string())
94 }
95}