Skip to main content

tauri/ipc/
capability_builder.rs

1// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
2// SPDX-License-Identifier: Apache-2.0
3// SPDX-License-Identifier: MIT
4
5use serde::Serialize;
6use tauri_utils::{
7  acl::{
8    Scopes,
9    capability::{Capability, CapabilityFile, PermissionEntry},
10  },
11  platform::Target,
12};
13
14/// A capability that can be added at runtime.
15pub trait RuntimeCapability {
16  /// Creates the capability file.
17  fn build(self) -> CapabilityFile;
18}
19
20impl<T: AsRef<str>> RuntimeCapability for T {
21  fn build(self) -> CapabilityFile {
22    self.as_ref().parse().expect("invalid capability")
23  }
24}
25
26/// A builder for a [`Capability`].
27pub struct CapabilityBuilder(Capability);
28
29impl CapabilityBuilder {
30  /// Creates a new capability builder with a unique identifier.
31  pub fn new(identifier: impl Into<String>) -> Self {
32    Self(Capability {
33      identifier: identifier.into(),
34      description: "".into(),
35      remote: None,
36      local: true,
37      windows: Vec::new(),
38      webviews: Vec::new(),
39      permissions: Vec::new(),
40      platforms: None,
41    })
42  }
43
44  /// Allows this capability to be used by a remote URL.
45  pub fn remote(mut self, url: String) -> Self {
46    self
47      .0
48      .remote
49      .get_or_insert_with(Default::default)
50      .urls
51      .push(url);
52    self
53  }
54
55  /// Whether this capability is applied on local app URLs or not. Defaults to `true`.
56  pub fn local(mut self, local: bool) -> Self {
57    self.0.local = local;
58    self
59  }
60
61  /// Link this capability to the given window label.
62  pub fn window(mut self, window: impl Into<String>) -> Self {
63    self.0.windows.push(window.into());
64    self
65  }
66
67  /// Link this capability to the a list of window labels.
68  pub fn windows(mut self, windows: impl IntoIterator<Item = impl Into<String>>) -> Self {
69    self.0.windows.extend(windows.into_iter().map(|w| w.into()));
70    self
71  }
72
73  /// Link this capability to the given webview label.
74  pub fn webview(mut self, webview: impl Into<String>) -> Self {
75    self.0.webviews.push(webview.into());
76    self
77  }
78
79  /// Link this capability to the a list of window labels.
80  pub fn webviews(mut self, webviews: impl IntoIterator<Item = impl Into<String>>) -> Self {
81    self
82      .0
83      .webviews
84      .extend(webviews.into_iter().map(|w| w.into()));
85    self
86  }
87
88  /// Add a new permission to this capability.
89  pub fn permission(mut self, permission: impl Into<String>) -> Self {
90    let permission = permission.into();
91    self.0.permissions.push(PermissionEntry::PermissionRef(
92      permission
93        .clone()
94        .try_into()
95        .unwrap_or_else(|_| panic!("invalid permission identifier '{permission}'")),
96    ));
97    self
98  }
99
100  /// Add a new scoped permission to this capability.
101  pub fn permission_scoped<T: Serialize>(
102    mut self,
103    permission: impl Into<String>,
104    allowed: Vec<T>,
105    denied: Vec<T>,
106  ) -> Self {
107    let permission = permission.into();
108    let identifier = permission
109      .clone()
110      .try_into()
111      .unwrap_or_else(|_| panic!("invalid permission identifier '{permission}'"));
112
113    let allowed_scope = allowed
114      .into_iter()
115      .map(|a| {
116        serde_json::to_value(a)
117          .expect("failed to serialize scope")
118          .into()
119      })
120      .collect();
121    let denied_scope = denied
122      .into_iter()
123      .map(|a| {
124        serde_json::to_value(a)
125          .expect("failed to serialize scope")
126          .into()
127      })
128      .collect();
129    let scope = Scopes {
130      allow: Some(allowed_scope),
131      deny: Some(denied_scope),
132    };
133
134    self
135      .0
136      .permissions
137      .push(PermissionEntry::ExtendedPermission { identifier, scope });
138    self
139  }
140
141  /// Adds a target platform for this capability.
142  ///
143  /// By default all platforms are applied.
144  pub fn platform(mut self, platform: Target) -> Self {
145    self
146      .0
147      .platforms
148      .get_or_insert_with(Default::default)
149      .push(platform);
150    self
151  }
152
153  /// Adds target platforms for this capability.
154  ///
155  /// By default all platforms are applied.
156  pub fn platforms(mut self, platforms: impl IntoIterator<Item = Target>) -> Self {
157    self
158      .0
159      .platforms
160      .get_or_insert_with(Default::default)
161      .extend(platforms);
162    self
163  }
164}
165
166impl RuntimeCapability for CapabilityBuilder {
167  fn build(self) -> CapabilityFile {
168    CapabilityFile::Capability(self.0)
169  }
170}