Hide surrealdb-core capabilities struct and implement builder. ()

Co-authored-by: Gerard Guillemas Martos <gguillemas@users.noreply.github.com>
This commit is contained in:
Mees Delzenne 2024-06-17 16:30:30 +02:00 committed by GitHub
parent 3321c64df7
commit 26de6072aa
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 397 additions and 22 deletions

View file

@ -304,8 +304,8 @@ pub fn connect(address: impl IntoEndpoint) -> Connect<Any, Surreal<Any>> {
#[cfg(all(test, feature = "kv-mem"))]
mod tests {
use super::*;
use crate::dbs::Capabilities;
use crate::opt::auth::Root;
use crate::opt::capabilities::Capabilities;
use crate::sql;
use crate::sql::Value;

View file

@ -8,6 +8,7 @@ use crate::sql::Value;
use serde::Serialize;
use std::io;
use std::path::PathBuf;
use surrealdb_core::dbs::capabilities::{ParseFuncTargetError, ParseNetTargetError};
use thiserror::Error;
/// An error originating from a remote SurrealDB database
@ -206,6 +207,24 @@ pub enum Error {
/// Tried to insert on an edge or edges
#[error("Insert queries on edges not supported: {0}")]
InsertOnEdges(Edges),
#[error("{0}")]
InvalidNetTarget(#[from] ParseNetTargetError),
#[error("{0}")]
InvalidFuncTarget(#[from] ParseFuncTargetError),
}
impl From<ParseNetTargetError> for crate::Error {
fn from(e: ParseNetTargetError) -> Self {
Self::Api(Error::from(e))
}
}
impl From<ParseFuncTargetError> for crate::Error {
fn from(e: ParseFuncTargetError) -> Self {
Self::Api(Error::from(e))
}
}
#[cfg(feature = "protocol-http")]

View file

@ -1,5 +1,12 @@
//! The capabilities that can be enabled for a database instance
use std::collections::HashSet;
use surrealdb_core::dbs::capabilities::{
Capabilities as CoreCapabilities, FuncTarget, NetTarget, ParseFuncTargetError,
ParseNetTargetError, Targets,
};
/// Capabilities are used to limit what a user can do to the system.
///
/// Capabilities are split into 4 categories:
@ -16,6 +23,31 @@
///
/// The capabilities are defined using allow/deny lists for fine-grained control.
///
/// # Filtering functions and net-targets.
///
/// The filtering of net targets and functions is done with an allow/deny list.
/// These list can either match everything, nothing or a given list.
///
/// By default every function and net-target is disallowed. For a function or net target to be
/// allowed it must match the allow-list and not match the deny-list. This means that if for
/// example a function is both in the allow-list and in the deny-list it will be disallowed.
///
/// With the combination of both these lists you can filter subgroups. For example:
/// ```
/// # use surrealdb::opt::capabilities::Capabilities;
/// # fn cap() -> surrealdb::Result<Capabilities>{
/// # let cap =
/// Capabilities::none()
/// .with_allow_function("http::*")?
/// .with_deny_function("http::post")?
///
/// # ;
/// # Ok(cap)
/// # }
/// ```
///
/// Will allow all and only all `http::*` functions except the function `http::post`.
///
/// Examples:
/// - Allow all functions: `--allow-funcs`
/// - Allow all functions except `http.*`: `--allow-funcs --deny-funcs 'http.*'`
@ -38,31 +70,357 @@
/// # Ok(())
/// # }
/// ```
///
/// Create a new instance, and allow certain functions
#[cfg_attr(feature = "kv-rocksdb", doc = "```no_run")]
#[cfg_attr(not(feature = "kv-rocksdb"), doc = "```ignore")]
/// # use std::str::FromStr;
/// # use surrealdb::engine::local::File;
/// # use surrealdb::opt::capabilities::Capabilities;
/// # use surrealdb::opt::capabilities::FuncTarget;
/// # use surrealdb::opt::capabilities::Targets;
/// # use surrealdb::opt::Config;
/// # use surrealdb::Surreal;
/// # #[tokio::main]
/// # async fn main() -> surrealdb::Result<()> {
/// let capabilities = Capabilities::default()
/// .with_functions(Targets::<FuncTarget>::All)
/// .without_functions(Targets::<FuncTarget>::Some(
/// [FuncTarget::from_str("http::*").unwrap()].into(),
/// ));
/// .with_deny_function("http::*")?;
/// let config = Config::default().capabilities(capabilities);
/// let db = Surreal::new::<File>(("temp.db", config)).await?;
/// # Ok(())
/// # }
/// ```
pub use crate::dbs::Capabilities;
///
#[derive(Debug, Clone)]
pub struct Capabilities {
cap: CoreCapabilities,
allow_funcs: Targets<FuncTarget>,
deny_funcs: Targets<FuncTarget>,
allow_net: Targets<NetTarget>,
deny_net: Targets<NetTarget>,
}
pub use crate::dbs::capabilities::FuncTarget;
pub use crate::dbs::capabilities::NetTarget;
pub use crate::dbs::capabilities::Targets;
impl Default for Capabilities {
fn default() -> Self {
Self::new()
}
}
impl Capabilities {
/// Create a builder with default capabilities enabled.
///
/// Default capabilities enables live query notifications and all (non-scripting) functions.
pub fn new() -> Self {
Capabilities {
cap: CoreCapabilities::default(),
allow_funcs: Targets::All,
deny_funcs: Targets::None,
allow_net: Targets::None,
deny_net: Targets::None,
}
}
/// Create a builder with all capabilities enabled.
pub fn all() -> Self {
Capabilities {
cap: CoreCapabilities::all(),
allow_funcs: Targets::All,
deny_funcs: Targets::None,
allow_net: Targets::All,
deny_net: Targets::None,
}
}
/// Create a builder with all capabilities disabled.
pub fn none() -> Self {
Capabilities {
cap: CoreCapabilities::default(),
allow_funcs: Targets::None,
deny_funcs: Targets::None,
allow_net: Targets::None,
deny_net: Targets::None,
}
}
/// Set whether to enable the embedded javascript scripting runtime.
pub fn with_scripting(self, enabled: bool) -> Self {
Self {
cap: self.cap.with_scripting(enabled),
..self
}
}
/// Set whether to allow non-authenticated users to execute queries when authentication is
/// enabled.
pub fn with_guest_access(self, enabled: bool) -> Self {
Self {
cap: self.cap.with_guest_access(enabled),
..self
}
}
/// Set wether to enable live query notifications.
pub fn with_live_query_notifications(self, enabled: bool) -> Self {
Self {
cap: self.cap.with_live_query_notifications(enabled),
..self
}
}
/// Set the allow list to allow all functions
pub fn allow_all_functions(&mut self) -> &mut Self {
self.allow_funcs = Targets::All;
self
}
/// Set the allow list to allow all functions
pub fn with_allow_all_functions(mut self) -> Self {
self.allow_all_functions();
self
}
/// Set the deny list to deny all functions
pub fn deny_all_functions(&mut self) -> &mut Self {
self.deny_funcs = Targets::All;
self
}
/// Set the deny list to deny all functions
pub fn with_deny_all_function(mut self) -> Self {
self.deny_all_functions();
self
}
/// Set the allow list to allow no function
pub fn allow_none_functions(&mut self) -> &mut Self {
self.allow_funcs = Targets::None;
self
}
/// Set the allow list to allow no function
pub fn with_allow_none_functions(mut self) -> Self {
self.allow_none_functions();
self
}
/// Set the deny list to deny no function
pub fn deny_none_functions(&mut self) -> &mut Self {
self.deny_funcs = Targets::None;
self
}
/// Set the deny list to deny no function
pub fn with_deny_none_function(mut self) -> Self {
self.deny_none_functions();
self
}
/// Add a function to the allow lists
///
/// Adding a function to the allow list overwrites previously set allow-all or allow-none
/// filters.
pub fn allow_function<S: AsRef<str>>(
&mut self,
func: S,
) -> Result<&mut Self, ParseFuncTargetError> {
self.allow_function_str(func.as_ref())
}
/// Add a function to the allow lists
///
/// Adding a function to the allow list overwrites previously set allow-all or allow-none
/// filters.
pub fn with_allow_function<S: AsRef<str>>(
mut self,
func: S,
) -> Result<Self, ParseFuncTargetError> {
self.allow_function(func)?;
Ok(self)
}
fn allow_function_str(&mut self, s: &str) -> Result<&mut Self, ParseFuncTargetError> {
let target: FuncTarget = s.parse()?;
match self.allow_funcs {
Targets::None | Targets::All => {
let mut set = HashSet::new();
set.insert(target);
self.allow_funcs = Targets::Some(set);
}
Targets::Some(ref mut x) => {
x.insert(target);
}
_ => unreachable!(),
}
Ok(self)
}
/// Add a function to the deny lists
///
/// Adding a function to the deny list overwrites previously set deny-all or deny-none
/// filters.
pub fn deny_function<S: AsRef<str>>(
&mut self,
func: S,
) -> Result<&mut Self, ParseFuncTargetError> {
self.deny_function_str(func.as_ref())
}
/// Add a function to the deny lists
///
/// Adding a function to the deny list overwrites previously set deny-all or deny-none
/// filters.
pub fn with_deny_function<S: AsRef<str>>(
mut self,
func: S,
) -> Result<Self, ParseFuncTargetError> {
self.deny_function(func)?;
Ok(self)
}
fn deny_function_str(&mut self, s: &str) -> Result<&mut Self, ParseFuncTargetError> {
let target: FuncTarget = s.parse()?;
match self.deny_funcs {
Targets::None | Targets::All => {
let mut set = HashSet::new();
set.insert(target);
self.deny_funcs = Targets::Some(set);
}
Targets::Some(ref mut x) => {
x.insert(target);
}
_ => unreachable!(),
}
Ok(self)
}
/// Set the allow list to allow all net targets
pub fn allow_all_net_targets(&mut self) -> &mut Self {
self.allow_net = Targets::All;
self
}
/// Set the allow list to allow all net targets
pub fn with_allow_all_net_targets(mut self) -> Self {
self.allow_all_net_targets();
self
}
/// Set the deny list to deny all net targets
pub fn deny_all_net_targets(&mut self) -> &mut Self {
self.deny_net = Targets::All;
self
}
/// Set the deny list to deny all net targets
pub fn with_deny_all_net_target(mut self) -> Self {
self.deny_all_net_targets();
self
}
/// Set the allow list to allow no net targets
pub fn allow_none_net_targets(&mut self) -> &mut Self {
self.allow_net = Targets::None;
self
}
/// Set the allow list to allow no net targets
pub fn with_allow_none_net_targets(mut self) -> Self {
self.allow_none_net_targets();
self
}
/// Set the deny list to deny no net targets
pub fn deny_none_net_targets(&mut self) -> &mut Self {
self.deny_net = Targets::None;
self
}
/// Set the deny list to deny no net targets
pub fn with_deny_none_net_target(mut self) -> Self {
self.deny_none_net_targets();
self
}
/// Add a net target to the allow lists
///
/// Adding a net target to the allow list overwrites previously set allow-all or allow-none
/// filters.
pub fn allow_net_target<S: AsRef<str>>(
&mut self,
func: S,
) -> Result<&mut Self, ParseNetTargetError> {
self.allow_net_target_str(func.as_ref())
}
/// Add a net target to the allow lists
///
/// Adding a net target to the allow list overwrites previously set allow-all or allow-none
/// filters.
pub fn with_allow_net_target<S: AsRef<str>>(
mut self,
func: S,
) -> Result<Self, ParseNetTargetError> {
self.allow_net_target(func)?;
Ok(self)
}
fn allow_net_target_str(&mut self, s: &str) -> Result<&mut Self, ParseNetTargetError> {
let target = s.parse()?;
match self.allow_net {
Targets::None | Targets::All => {
let mut set = HashSet::new();
set.insert(target);
self.allow_net = Targets::Some(set);
}
Targets::Some(ref mut x) => {
x.insert(target);
}
_ => unreachable!(),
}
Ok(self)
}
/// Add a net target to the deny lists
///
/// Adding a net target to the deny list overwrites previously set deny-all or deny-none
/// filters.
pub fn deny_net_target<S: AsRef<str>>(
&mut self,
func: S,
) -> Result<&mut Self, ParseNetTargetError> {
self.deny_net_target_str(func.as_ref())
}
/// Add a net target to the deny lists
///
/// Adding a net target to the deny list overwrites previously set deny-all or deny-none
/// filters.
pub fn with_deny_net_target<S: AsRef<str>>(
mut self,
func: S,
) -> Result<Self, ParseNetTargetError> {
self.deny_net_target(func)?;
Ok(self)
}
fn deny_net_target_str(&mut self, s: &str) -> Result<&mut Self, ParseNetTargetError> {
let target = s.parse()?;
match self.deny_net {
Targets::None | Targets::All => {
let mut set = HashSet::new();
set.insert(target);
self.deny_net = Targets::Some(set);
}
Targets::Some(ref mut x) => {
x.insert(target);
}
_ => unreachable!(),
}
Ok(self)
}
pub(crate) fn build(self) -> CoreCapabilities {
self.cap
.with_functions(self.allow_funcs)
.without_functions(self.deny_funcs)
.with_network_targets(self.allow_net)
.without_network_targets(self.deny_net)
}
}

View file

@ -1,4 +1,4 @@
use crate::{dbs::Capabilities, iam::Level};
use crate::opt::capabilities::Capabilities;
#[cfg(any(
feature = "kv-mem",
feature = "kv-surrealkv",
@ -8,6 +8,7 @@ use crate::{dbs::Capabilities, iam::Level};
))]
use std::path::PathBuf;
use std::time::Duration;
use surrealdb_core::{dbs::Capabilities as CoreCapabilities, iam::Level};
/// Configuration for server connection, including: strictness, notifications, query_timeout, transaction_timeout
#[derive(Debug, Clone, Default)]
@ -24,7 +25,7 @@ pub struct Config {
pub(crate) username: String,
pub(crate) password: String,
pub(crate) tick_interval: Option<Duration>,
pub(crate) capabilities: Capabilities,
pub(crate) capabilities: CoreCapabilities,
#[cfg(any(
feature = "kv-mem",
feature = "kv-surrealkv",
@ -117,7 +118,7 @@ impl Config {
/// Set the capabilities for the database
pub fn capabilities(mut self, capabilities: Capabilities) -> Self {
self.capabilities = capabilities;
self.capabilities = capabilities.build();
self
}

View file

@ -12,7 +12,6 @@ mod api_integration {
use std::sync::Arc;
use std::sync::Mutex;
use std::time::Duration;
use surrealdb::dbs::capabilities::Capabilities;
use surrealdb::error::Api as ApiError;
use surrealdb::error::Db as DbError;
use surrealdb::opt::auth::Database;
@ -20,6 +19,7 @@ mod api_integration {
use surrealdb::opt::auth::Namespace;
use surrealdb::opt::auth::Record as RecordAccess;
use surrealdb::opt::auth::Root;
use surrealdb::opt::capabilities::Capabilities;
use surrealdb::opt::Config;
use surrealdb::opt::PatchOp;
use surrealdb::opt::Resource;

View file

@ -4,9 +4,8 @@ use crate::cli::abstraction::{
};
use crate::err::Error;
use clap::Args;
use surrealdb::dbs::Capabilities;
use surrealdb::engine::any::{connect, IntoEndpoint};
use surrealdb::opt::Config;
use surrealdb::opt::{capabilities::Capabilities, Config};
#[derive(Args, Debug)]
pub struct ImportCommandArguments {

View file

@ -4,9 +4,8 @@ use crate::cli::abstraction::{
};
use crate::err::Error;
use clap::Args;
use surrealdb::dbs::Capabilities;
use surrealdb::engine::any::{connect, IntoEndpoint};
use surrealdb::opt::Config;
use surrealdb::opt::{capabilities::Capabilities, Config};
#[derive(Args, Debug)]
pub struct ImportCommandArguments {

View file

@ -11,10 +11,9 @@ use rustyline::validate::{ValidationContext, ValidationResult, Validator};
use rustyline::{Completer, Editor, Helper, Highlighter, Hinter};
use serde::Serialize;
use serde_json::ser::PrettyFormatter;
use surrealdb::dbs::Capabilities;
use surrealdb::engine::any::{connect, IntoEndpoint};
use surrealdb::method::{Stats, WithStats};
use surrealdb::opt::Config;
use surrealdb::opt::{capabilities::Capabilities, Config};
use surrealdb::sql::{self, Statement, Value};
use surrealdb::{Notification, Response};