Ensure system parameters are not able to be overridden
This commit is contained in:
parent
ed18003223
commit
65f219ffe5
6 changed files with 81 additions and 11 deletions
|
@ -5,6 +5,9 @@ pub const MAX_CONCURRENT_TASKS: usize = 64;
|
||||||
/// Specifies how deep various forms of computation will go before the query fails.
|
/// Specifies how deep various forms of computation will go before the query fails.
|
||||||
pub const MAX_COMPUTATION_DEPTH: u8 = 30;
|
pub const MAX_COMPUTATION_DEPTH: u8 = 30;
|
||||||
|
|
||||||
|
/// Specifies the names of parameters which can not be specified in a query.
|
||||||
|
pub const PROTECTED_PARAM_NAMES: &[&str] = &["auth", "scope", "token", "session"];
|
||||||
|
|
||||||
/// The characters which are supported in server record IDs.
|
/// The characters which are supported in server record IDs.
|
||||||
pub const ID_CHARS: [char; 36] = [
|
pub const ID_CHARS: [char; 36] = [
|
||||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i',
|
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i',
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use crate::cnf::PROTECTED_PARAM_NAMES;
|
||||||
use crate::ctx::Context;
|
use crate::ctx::Context;
|
||||||
use crate::dbs::response::Response;
|
use crate::dbs::response::Response;
|
||||||
use crate::dbs::Auth;
|
use crate::dbs::Auth;
|
||||||
|
@ -229,9 +230,16 @@ impl<'a> Executor<'a> {
|
||||||
true => Err(Error::TxFailure),
|
true => Err(Error::TxFailure),
|
||||||
// The transaction began successfully
|
// The transaction began successfully
|
||||||
false => {
|
false => {
|
||||||
// Process the statement
|
// Check if the variable is a protected variable
|
||||||
let res = stm.compute(&ctx, &opt, &self.txn(), None).await;
|
let res = match PROTECTED_PARAM_NAMES.contains(&stm.name.as_str()) {
|
||||||
//
|
// The variable isn't protected and can be stored
|
||||||
|
false => stm.compute(&ctx, &opt, &self.txn(), None).await,
|
||||||
|
// The user tried to set a protected variable
|
||||||
|
true => Err(Error::InvalidParam {
|
||||||
|
name: stm.name.to_owned(),
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
// Check the statement
|
||||||
match res {
|
match res {
|
||||||
Ok(val) => {
|
Ok(val) => {
|
||||||
// Set the parameter
|
// Set the parameter
|
||||||
|
|
|
@ -1,23 +1,35 @@
|
||||||
|
use crate::cnf::PROTECTED_PARAM_NAMES;
|
||||||
use crate::ctx::Context;
|
use crate::ctx::Context;
|
||||||
|
use crate::err::Error;
|
||||||
use crate::sql::value::Value;
|
use crate::sql::value::Value;
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
pub type Variables = Option<BTreeMap<String, Value>>;
|
pub type Variables = Option<BTreeMap<String, Value>>;
|
||||||
|
|
||||||
pub(crate) trait Attach {
|
pub(crate) trait Attach {
|
||||||
fn attach(self, ctx: Context) -> Context;
|
fn attach(self, ctx: Context) -> Result<Context, Error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Attach for Variables {
|
impl Attach for Variables {
|
||||||
fn attach(self, mut ctx: Context) -> Context {
|
fn attach(self, mut ctx: Context) -> Result<Context, Error> {
|
||||||
match self {
|
match self {
|
||||||
Some(m) => {
|
Some(m) => {
|
||||||
for (key, val) in m {
|
for (key, val) in m {
|
||||||
ctx.add_value(key, val);
|
// Check if the variable is a protected variable
|
||||||
}
|
match PROTECTED_PARAM_NAMES.contains(&key.as_str()) {
|
||||||
ctx
|
// The variable isn't protected and can be stored
|
||||||
}
|
false => ctx.add_value(key, val),
|
||||||
None => ctx,
|
// The user tried to set a protected variable
|
||||||
|
true => {
|
||||||
|
return Err(Error::InvalidParam {
|
||||||
|
name: key,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(ctx)
|
||||||
|
}
|
||||||
|
None => Ok(ctx),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,6 +79,12 @@ pub enum Error {
|
||||||
#[error("Remote HTTP request functions are not enabled")]
|
#[error("Remote HTTP request functions are not enabled")]
|
||||||
HttpDisabled,
|
HttpDisabled,
|
||||||
|
|
||||||
|
/// it is not possible to set a variable with the specified name
|
||||||
|
#[error("Found '{name}' but it is not possible to set a variable with this name")]
|
||||||
|
InvalidParam {
|
||||||
|
name: String,
|
||||||
|
},
|
||||||
|
|
||||||
/// The LIMIT clause must evaluate to a positive integer
|
/// The LIMIT clause must evaluate to a positive integer
|
||||||
#[error("Found {value} but the LIMIT clause must evaluate to a positive integer")]
|
#[error("Found {value} but the LIMIT clause must evaluate to a positive integer")]
|
||||||
InvalidLimit {
|
InvalidLimit {
|
||||||
|
|
|
@ -239,7 +239,7 @@ impl Datastore {
|
||||||
// Start an execution context
|
// Start an execution context
|
||||||
let ctx = sess.context(ctx);
|
let ctx = sess.context(ctx);
|
||||||
// Store the query variables
|
// Store the query variables
|
||||||
let ctx = vars.attach(ctx);
|
let ctx = vars.attach(ctx)?;
|
||||||
// Parse the SQL query text
|
// Parse the SQL query text
|
||||||
let ast = sql::parse(txt)?;
|
let ast = sql::parse(txt)?;
|
||||||
// Setup the auth options
|
// Setup the auth options
|
||||||
|
@ -288,7 +288,7 @@ impl Datastore {
|
||||||
// Start an execution context
|
// Start an execution context
|
||||||
let ctx = sess.context(ctx);
|
let ctx = sess.context(ctx);
|
||||||
// Store the query variables
|
// Store the query variables
|
||||||
let ctx = vars.attach(ctx);
|
let ctx = vars.attach(ctx)?;
|
||||||
// Setup the auth options
|
// Setup the auth options
|
||||||
opt.auth = sess.au.clone();
|
opt.auth = sess.au.clone();
|
||||||
// Setup the live options
|
// Setup the live options
|
||||||
|
@ -338,7 +338,7 @@ impl Datastore {
|
||||||
// Start an execution context
|
// Start an execution context
|
||||||
let ctx = sess.context(ctx);
|
let ctx = sess.context(ctx);
|
||||||
// Store the query variables
|
// Store the query variables
|
||||||
let ctx = vars.attach(ctx);
|
let ctx = vars.attach(ctx)?;
|
||||||
// Setup the auth options
|
// Setup the auth options
|
||||||
opt.auth = sess.au.clone();
|
opt.auth = sess.au.clone();
|
||||||
// Set current NS and DB
|
// Set current NS and DB
|
||||||
|
|
41
lib/tests/param.rs
Normal file
41
lib/tests/param.rs
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
mod parse;
|
||||||
|
use parse::Parse;
|
||||||
|
use surrealdb::sql::Value;
|
||||||
|
use surrealdb::Datastore;
|
||||||
|
use surrealdb::Error;
|
||||||
|
use surrealdb::Session;
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn define_protected_param() -> Result<(), Error> {
|
||||||
|
let sql = "
|
||||||
|
LET $test = { some: 'thing', other: true };
|
||||||
|
SELECT * FROM $test WHERE some = 'thing';
|
||||||
|
LET $auth = { ID: admin:tester };
|
||||||
|
";
|
||||||
|
let dbs = Datastore::new("memory").await?;
|
||||||
|
let ses = Session::for_kv().with_ns("test").with_db("test");
|
||||||
|
let res = &mut dbs.execute(&sql, &ses, None, false).await?;
|
||||||
|
assert_eq!(res.len(), 3);
|
||||||
|
//
|
||||||
|
let tmp = res.remove(0).result;
|
||||||
|
assert!(tmp.is_ok());
|
||||||
|
//
|
||||||
|
let tmp = res.remove(0).result?;
|
||||||
|
let val = Value::parse(
|
||||||
|
"[
|
||||||
|
{
|
||||||
|
other: true,
|
||||||
|
some: 'thing'
|
||||||
|
}
|
||||||
|
]",
|
||||||
|
);
|
||||||
|
assert_eq!(tmp, val);
|
||||||
|
//
|
||||||
|
let tmp = res.remove(0).result;
|
||||||
|
assert!(matches!(
|
||||||
|
tmp.err(),
|
||||||
|
Some(e) if e.to_string() == r#"Found 'auth' but it is not possible to set a variable with this name"#
|
||||||
|
));
|
||||||
|
//
|
||||||
|
Ok(())
|
||||||
|
}
|
Loading…
Reference in a new issue