surrealdb/api/opt/
capabilities.rs

1//! The capabilities that can be enabled for a database instance
2
3use std::collections::HashSet;
4
5use surrealdb_core::dbs::capabilities::{
6	Capabilities as CoreCapabilities, FuncTarget, NetTarget, ParseFuncTargetError,
7	ParseNetTargetError, Targets,
8};
9
10/// Capabilities are used to limit what a user can do to the system.
11///
12/// Capabilities are split into 4 categories:
13/// - Scripting: Whether or not the user can execute scripts
14/// - Guest access: Whether or not a non-authenticated user can execute queries on the system when authentication is enabled.
15/// - Functions: Whether or not the user can execute certain functions
16/// - Network: Whether or not the user can access certain network addresses
17///
18/// Capabilities are configured globally. By default, capabilities are configured as:
19/// - Scripting: false
20/// - Guest access: false
21/// - Functions: All functions are allowed
22/// - Network: No network address is allowed nor denied, hence all network addresses are denied unless explicitly allowed
23///
24/// The capabilities are defined using allow/deny lists for fine-grained control.
25///
26/// # Filtering functions and net-targets.
27///
28/// The filtering of net targets and functions is done with an allow/deny list.
29/// These list can either match everything, nothing or a given list.
30///
31/// By default every function and net-target is disallowed. For a function or net target to be
32/// allowed it must match the allow-list and not match the deny-list. This means that if for
33/// example a function is both in the allow-list and in the deny-list it will be disallowed.
34///
35/// With the combination of both these lists you can filter subgroups. For example:
36/// ```
37/// # use surrealdb::opt::capabilities::Capabilities;
38/// # fn cap() -> surrealdb::Result<Capabilities>{
39/// # let cap =
40/// Capabilities::none()
41///     .with_allow_function("http::*")?
42///     .with_deny_function("http::post")?
43///
44///  # ;
45///  # Ok(cap)
46/// # }
47/// ```
48///
49/// Will allow all and only all `http::*` functions except the function `http::post`.
50///
51/// Examples:
52/// - Allow all functions: `--allow-funcs`
53/// - Allow all functions except `http.*`: `--allow-funcs --deny-funcs 'http.*'`
54/// - Allow all network addresses except AWS metadata endpoint: `--allow-net --deny-net='169.254.169.254'`
55///
56/// # Examples
57///
58/// Create a new instance, and allow all capabilities
59#[cfg_attr(feature = "kv-rocksdb", doc = "```no_run")]
60#[cfg_attr(not(feature = "kv-rocksdb"), doc = "```ignore")]
61/// # use surrealdb::opt::capabilities::Capabilities;
62/// # use surrealdb::opt::Config;
63/// # use surrealdb::Surreal;
64/// # use surrealdb::engine::local::File;
65/// # #[tokio::main]
66/// # async fn main() -> surrealdb::Result<()> {
67/// let capabilities = Capabilities::all();
68/// let config = Config::default().capabilities(capabilities);
69/// let db = Surreal::new::<File>(("temp.db", config)).await?;
70/// # Ok(())
71/// # }
72/// ```
73/// Create a new instance, and allow certain functions
74#[cfg_attr(feature = "kv-rocksdb", doc = "```no_run")]
75#[cfg_attr(not(feature = "kv-rocksdb"), doc = "```ignore")]
76/// # use std::str::FromStr;
77/// # use surrealdb::engine::local::File;
78/// # use surrealdb::opt::capabilities::Capabilities;
79/// # use surrealdb::opt::Config;
80/// # use surrealdb::Surreal;
81/// # #[tokio::main]
82/// # async fn main() -> surrealdb::Result<()> {
83/// let capabilities = Capabilities::default()
84///     .with_deny_function("http::*")?;
85/// let config = Config::default().capabilities(capabilities);
86/// let db = Surreal::new::<File>(("temp.db", config)).await?;
87/// # Ok(())
88/// # }
89/// ```
90///
91#[derive(Debug, Clone)]
92pub struct Capabilities {
93	cap: CoreCapabilities,
94	allow_funcs: Targets<FuncTarget>,
95	deny_funcs: Targets<FuncTarget>,
96	allow_net: Targets<NetTarget>,
97	deny_net: Targets<NetTarget>,
98}
99
100impl Default for Capabilities {
101	fn default() -> Self {
102		Self::new()
103	}
104}
105
106impl Capabilities {
107	/// Create a builder with default capabilities enabled.
108	///
109	/// Default capabilities enables live query notifications and all (non-scripting) functions.
110	pub fn new() -> Self {
111		Capabilities {
112			cap: CoreCapabilities::default(),
113			allow_funcs: Targets::All,
114			deny_funcs: Targets::None,
115			allow_net: Targets::None,
116			deny_net: Targets::None,
117		}
118	}
119
120	/// Create a builder with all capabilities enabled.
121	pub fn all() -> Self {
122		Capabilities {
123			cap: CoreCapabilities::all(),
124			allow_funcs: Targets::All,
125			deny_funcs: Targets::None,
126			allow_net: Targets::All,
127			deny_net: Targets::None,
128		}
129	}
130
131	/// Create a builder with all capabilities disabled.
132	pub fn none() -> Self {
133		Capabilities {
134			cap: CoreCapabilities::none(),
135			allow_funcs: Targets::None,
136			deny_funcs: Targets::None,
137			allow_net: Targets::None,
138			deny_net: Targets::None,
139		}
140	}
141
142	/// Set whether to enable the embedded javascript scripting runtime.
143	pub fn with_scripting(self, enabled: bool) -> Self {
144		Self {
145			cap: self.cap.with_scripting(enabled),
146			..self
147		}
148	}
149
150	/// Set whether to allow non-authenticated users to execute queries when authentication is
151	/// enabled.
152	pub fn with_guest_access(self, enabled: bool) -> Self {
153		Self {
154			cap: self.cap.with_guest_access(enabled),
155			..self
156		}
157	}
158
159	/// Set wether to enable live query notifications.
160	pub fn with_live_query_notifications(self, enabled: bool) -> Self {
161		Self {
162			cap: self.cap.with_live_query_notifications(enabled),
163			..self
164		}
165	}
166
167	/// Set the allow list to allow all functions
168	pub fn allow_all_functions(&mut self) -> &mut Self {
169		self.allow_funcs = Targets::All;
170		self
171	}
172
173	/// Set the allow list to allow all functions
174	pub fn with_allow_all_functions(mut self) -> Self {
175		self.allow_all_functions();
176		self
177	}
178
179	/// Set the deny list to deny all functions
180	pub fn deny_all_functions(&mut self) -> &mut Self {
181		self.deny_funcs = Targets::All;
182		self
183	}
184
185	/// Set the deny list to deny all functions
186	pub fn with_deny_all_functions(mut self) -> Self {
187		self.deny_all_functions();
188		self
189	}
190
191	/// Set the allow list to allow no function
192	pub fn allow_none_functions(&mut self) -> &mut Self {
193		self.allow_funcs = Targets::None;
194		self
195	}
196
197	/// Set the allow list to allow no function
198	pub fn with_allow_none_functions(mut self) -> Self {
199		self.allow_none_functions();
200		self
201	}
202
203	/// Set the deny list to deny no function
204	pub fn deny_none_functions(&mut self) -> &mut Self {
205		self.deny_funcs = Targets::None;
206		self
207	}
208
209	/// Set the deny list to deny no function
210	pub fn with_deny_none_function(mut self) -> Self {
211		self.deny_none_functions();
212		self
213	}
214
215	/// Add a function to the allow lists
216	///
217	/// Adding a function to the allow list overwrites previously set allow-all or allow-none
218	/// filters.
219	pub fn allow_function<S: AsRef<str>>(
220		&mut self,
221		func: S,
222	) -> Result<&mut Self, ParseFuncTargetError> {
223		self.allow_function_str(func.as_ref())
224	}
225
226	/// Add a function to the allow lists
227	///
228	/// Adding a function to the allow list overwrites previously set allow-all or allow-none
229	/// filters.
230	pub fn with_allow_function<S: AsRef<str>>(
231		mut self,
232		func: S,
233	) -> Result<Self, ParseFuncTargetError> {
234		self.allow_function(func)?;
235		Ok(self)
236	}
237
238	fn allow_function_str(&mut self, s: &str) -> Result<&mut Self, ParseFuncTargetError> {
239		let target: FuncTarget = s.parse()?;
240		match self.allow_funcs {
241			Targets::None | Targets::All => {
242				let mut set = HashSet::new();
243				set.insert(target);
244				self.allow_funcs = Targets::Some(set);
245			}
246			Targets::Some(ref mut x) => {
247				x.insert(target);
248			}
249			_ => unreachable!(),
250		}
251		Ok(self)
252	}
253
254	/// Add a function to the deny lists
255	///
256	/// Adding a function to the deny list overwrites previously set deny-all or deny-none
257	/// filters.
258	pub fn deny_function<S: AsRef<str>>(
259		&mut self,
260		func: S,
261	) -> Result<&mut Self, ParseFuncTargetError> {
262		self.deny_function_str(func.as_ref())
263	}
264
265	/// Add a function to the deny lists
266	///
267	/// Adding a function to the deny list overwrites previously set deny-all or deny-none
268	/// filters.
269	pub fn with_deny_function<S: AsRef<str>>(
270		mut self,
271		func: S,
272	) -> Result<Self, ParseFuncTargetError> {
273		self.deny_function(func)?;
274		Ok(self)
275	}
276
277	fn deny_function_str(&mut self, s: &str) -> Result<&mut Self, ParseFuncTargetError> {
278		let target: FuncTarget = s.parse()?;
279		match self.deny_funcs {
280			Targets::None | Targets::All => {
281				let mut set = HashSet::new();
282				set.insert(target);
283				self.deny_funcs = Targets::Some(set);
284			}
285			Targets::Some(ref mut x) => {
286				x.insert(target);
287			}
288			_ => unreachable!(),
289		}
290		Ok(self)
291	}
292
293	/// Set the allow list to allow all net targets
294	pub fn allow_all_net_targets(&mut self) -> &mut Self {
295		self.allow_net = Targets::All;
296		self
297	}
298
299	/// Set the allow list to allow all net targets
300	pub fn with_allow_all_net_targets(mut self) -> Self {
301		self.allow_all_net_targets();
302		self
303	}
304
305	/// Set the deny list to deny all net targets
306	pub fn deny_all_net_targets(&mut self) -> &mut Self {
307		self.deny_net = Targets::All;
308		self
309	}
310
311	/// Set the deny list to deny all net targets
312	pub fn with_deny_all_net_targets(mut self) -> Self {
313		self.deny_all_net_targets();
314		self
315	}
316
317	/// Set the allow list to allow no net targets
318	pub fn allow_none_net_targets(&mut self) -> &mut Self {
319		self.allow_net = Targets::None;
320		self
321	}
322
323	/// Set the allow list to allow no net targets
324	pub fn with_allow_none_net_targets(mut self) -> Self {
325		self.allow_none_net_targets();
326		self
327	}
328
329	/// Set the deny list to deny no net targets
330	pub fn deny_none_net_targets(&mut self) -> &mut Self {
331		self.deny_net = Targets::None;
332		self
333	}
334
335	/// Set the deny list to deny no net targets
336	pub fn with_deny_none_net_target(mut self) -> Self {
337		self.deny_none_net_targets();
338		self
339	}
340
341	/// Add a net target to the allow lists
342	///
343	/// Adding a net target to the allow list overwrites previously set allow-all or allow-none
344	/// filters.
345	pub fn allow_net_target<S: AsRef<str>>(
346		&mut self,
347		func: S,
348	) -> Result<&mut Self, ParseNetTargetError> {
349		self.allow_net_target_str(func.as_ref())
350	}
351
352	/// Add a net target to the allow lists
353	///
354	/// Adding a net target to the allow list overwrites previously set allow-all or allow-none
355	/// filters.
356	pub fn with_allow_net_target<S: AsRef<str>>(
357		mut self,
358		func: S,
359	) -> Result<Self, ParseNetTargetError> {
360		self.allow_net_target(func)?;
361		Ok(self)
362	}
363
364	fn allow_net_target_str(&mut self, s: &str) -> Result<&mut Self, ParseNetTargetError> {
365		let target = s.parse()?;
366		match self.allow_net {
367			Targets::None | Targets::All => {
368				let mut set = HashSet::new();
369				set.insert(target);
370				self.allow_net = Targets::Some(set);
371			}
372			Targets::Some(ref mut x) => {
373				x.insert(target);
374			}
375			_ => unreachable!(),
376		}
377		Ok(self)
378	}
379
380	/// Add a net target to the deny lists
381	///
382	/// Adding a net target to the deny list overwrites previously set deny-all or deny-none
383	/// filters.
384	pub fn deny_net_target<S: AsRef<str>>(
385		&mut self,
386		func: S,
387	) -> Result<&mut Self, ParseNetTargetError> {
388		self.deny_net_target_str(func.as_ref())
389	}
390
391	/// Add a net target to the deny lists
392	///
393	/// Adding a net target to the deny list overwrites previously set deny-all or deny-none
394	/// filters.
395	pub fn with_deny_net_target<S: AsRef<str>>(
396		mut self,
397		func: S,
398	) -> Result<Self, ParseNetTargetError> {
399		self.deny_net_target(func)?;
400		Ok(self)
401	}
402
403	fn deny_net_target_str(&mut self, s: &str) -> Result<&mut Self, ParseNetTargetError> {
404		let target = s.parse()?;
405		match self.deny_net {
406			Targets::None | Targets::All => {
407				let mut set = HashSet::new();
408				set.insert(target);
409				self.deny_net = Targets::Some(set);
410			}
411			Targets::Some(ref mut x) => {
412				x.insert(target);
413			}
414			_ => unreachable!(),
415		}
416		Ok(self)
417	}
418
419	pub(crate) fn build(self) -> CoreCapabilities {
420		self.cap
421			.with_functions(self.allow_funcs)
422			.without_functions(self.deny_funcs)
423			.with_network_targets(self.allow_net)
424			.without_network_targets(self.deny_net)
425	}
426}