Skip to content

Commit

Permalink
Resolve panics when a NS or a DB are not configured (#4157)
Browse files Browse the repository at this point in the history
Co-authored-by: Emmanuel Keller <emmanuel.keller@surrealdb.com>
  • Loading branch information
gguillemas and emmanuel-keller committed Jun 11, 2024
1 parent a11f1bc commit d9ae887
Show file tree
Hide file tree
Showing 54 changed files with 442 additions and 326 deletions.
32 changes: 13 additions & 19 deletions core/src/dbs/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -339,13 +339,13 @@ impl Options {
}

/// Get currently selected NS
pub fn ns(&self) -> &str {
self.ns.as_ref().map(AsRef::as_ref).unwrap()
pub fn ns(&self) -> Result<&str, Error> {
self.ns.as_ref().map(AsRef::as_ref).ok_or(Error::NsEmpty)
}

/// Get currently selected DB
pub fn db(&self) -> &str {
self.db.as_ref().map(AsRef::as_ref).unwrap()
pub fn db(&self) -> Result<&str, Error> {
self.db.as_ref().map(AsRef::as_ref).ok_or(Error::DbEmpty)
}

/// Check whether this request supports realtime queries
Expand Down Expand Up @@ -379,14 +379,8 @@ impl Options {
// Validate the target resource and base
let res = match base {
Base::Root => res.on_root(),
Base::Ns => {
self.valid_for_ns()?;
res.on_ns(self.ns())
}
Base::Db => {
self.valid_for_db()?;
res.on_db(self.ns(), self.db())
}
Base::Ns => res.on_ns(self.ns()?),
Base::Db => res.on_db(self.ns()?, self.db()?),
// TODO(gguillemas): This variant is kept in 2.0.0 for backward compatibility. Drop in 3.0.0.
Base::Sc(_) => {
// We should not get here, the scope base is only used in parsing for backward compatibility.
Expand All @@ -406,15 +400,15 @@ impl Options {
///
/// TODO: This method is called a lot during data operations, so we decided to bypass the system's authorization mechanism.
/// This is a temporary solution, until we optimize the new authorization system.
pub fn check_perms(&self, action: Action) -> bool {
pub fn check_perms(&self, action: Action) -> Result<bool, Error> {
// If permissions are disabled, don't check permissions
if !self.perms {
return false;
return Ok(false);
}

// If auth is disabled and actor is anonymous, don't check permissions
if !self.auth_enabled && self.auth.is_anon() {
return false;
return Ok(false);
}

// Is the actor allowed to view?
Expand All @@ -424,10 +418,10 @@ impl Options {
let can_edit = [Role::Editor, Role::Owner].iter().any(|r| self.auth.has_role(r));
// Is the target database in the actor's level?
let db_in_actor_level = self.auth.is_root()
|| self.auth.is_ns() && self.auth.level().ns().unwrap() == self.ns()
|| self.auth.is_ns() && self.auth.level().ns().unwrap() == self.ns()?
|| self.auth.is_db()
&& self.auth.level().ns().unwrap() == self.ns()
&& self.auth.level().db().unwrap() == self.db();
&& self.auth.level().ns().unwrap() == self.ns()?
&& self.auth.level().db().unwrap() == self.db()?;

// Is the actor allowed to do the action on the selected database?
let is_allowed = match action {
Expand All @@ -442,7 +436,7 @@ impl Options {
};

// Check permissions if the author is not already allowed to do the action
!is_allowed
Ok(!is_allowed)
}
}

Expand Down
44 changes: 22 additions & 22 deletions core/src/dbs/processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,9 +187,9 @@ impl<'a> Processor<'a> {
v: Thing,
) -> Result<(), Error> {
// Check that the table exists
ctx.tx_lock().await.check_ns_db_tb(opt.ns(), opt.db(), &v.tb, opt.strict).await?;
ctx.tx_lock().await.check_ns_db_tb(opt.ns()?, opt.db()?, &v.tb, opt.strict).await?;
// Fetch the data from the store
let key = thing::new(opt.ns(), opt.db(), &v.tb, &v.id);
let key = thing::new(opt.ns()?, opt.db()?, &v.tb, &v.id);
let val = ctx.tx_lock().await.get(key).await?;
// Parse the data from the store
let val = Operable::Value(match val {
Expand All @@ -216,7 +216,7 @@ impl<'a> Processor<'a> {
v: Thing,
) -> Result<(), Error> {
// Check that the table exists
ctx.tx_lock().await.check_ns_db_tb(opt.ns(), opt.db(), &v.tb, opt.strict).await?;
ctx.tx_lock().await.check_ns_db_tb(opt.ns()?, opt.db()?, &v.tb, opt.strict).await?;
// Process the document record
let pro = Processed {
rid: Some(v),
Expand All @@ -238,9 +238,9 @@ impl<'a> Processor<'a> {
o: Value,
) -> Result<(), Error> {
// Check that the table exists
ctx.tx_lock().await.check_ns_db_tb(opt.ns(), opt.db(), &v.tb, opt.strict).await?;
ctx.tx_lock().await.check_ns_db_tb(opt.ns()?, opt.db()?, &v.tb, opt.strict).await?;
// Fetch the data from the store
let key = thing::new(opt.ns(), opt.db(), &v.tb, &v.id);
let key = thing::new(opt.ns()?, opt.db()?, &v.tb, &v.id);
let val = ctx.tx_lock().await.get(key).await?;
// Parse the data from the store
let x = match val {
Expand Down Expand Up @@ -273,9 +273,9 @@ impl<'a> Processor<'a> {
o: Option<Value>,
) -> Result<(), Error> {
// Check that the table exists
ctx.tx_lock().await.check_ns_db_tb(opt.ns(), opt.db(), &v.tb, opt.strict).await?;
ctx.tx_lock().await.check_ns_db_tb(opt.ns()?, opt.db()?, &v.tb, opt.strict).await?;
// Fetch the data from the store
let key = thing::new(opt.ns(), opt.db(), &v.tb, &v.id);
let key = thing::new(opt.ns()?, opt.db()?, &v.tb, &v.id);
let val = ctx.tx_lock().await.get(key).await?;
// Parse the data from the store
let x = match val {
Expand Down Expand Up @@ -304,10 +304,10 @@ impl<'a> Processor<'a> {
v: &Table,
) -> Result<(), Error> {
// Check that the table exists
ctx.tx_lock().await.check_ns_db_tb(opt.ns(), opt.db(), v, opt.strict).await?;
ctx.tx_lock().await.check_ns_db_tb(opt.ns()?, opt.db()?, v, opt.strict).await?;
// Prepare the start and end keys
let beg = thing::prefix(opt.ns(), opt.db(), v);
let end = thing::suffix(opt.ns(), opt.db(), v);
let beg = thing::prefix(opt.ns()?, opt.db()?, v);
let end = thing::suffix(opt.ns()?, opt.db()?, v);
// Loop until no more keys
let mut next_page = Some(ScanPage::from(beg..end));
while let Some(page) = next_page {
Expand Down Expand Up @@ -358,23 +358,23 @@ impl<'a> Processor<'a> {
v: Range,
) -> Result<(), Error> {
// Check that the table exists
ctx.tx_lock().await.check_ns_db_tb(opt.ns(), opt.db(), &v.tb, opt.strict).await?;
ctx.tx_lock().await.check_ns_db_tb(opt.ns()?, opt.db()?, &v.tb, opt.strict).await?;
// Prepare the range start key
let beg = match &v.beg {
Bound::Unbounded => thing::prefix(opt.ns(), opt.db(), &v.tb),
Bound::Included(id) => thing::new(opt.ns(), opt.db(), &v.tb, id).encode().unwrap(),
Bound::Unbounded => thing::prefix(opt.ns()?, opt.db()?, &v.tb),
Bound::Included(id) => thing::new(opt.ns()?, opt.db()?, &v.tb, id).encode().unwrap(),
Bound::Excluded(id) => {
let mut key = thing::new(opt.ns(), opt.db(), &v.tb, id).encode().unwrap();
let mut key = thing::new(opt.ns()?, opt.db()?, &v.tb, id).encode().unwrap();
key.push(0x00);
key
}
};
// Prepare the range end key
let end = match &v.end {
Bound::Unbounded => thing::suffix(opt.ns(), opt.db(), &v.tb),
Bound::Excluded(id) => thing::new(opt.ns(), opt.db(), &v.tb, id).encode().unwrap(),
Bound::Unbounded => thing::suffix(opt.ns()?, opt.db()?, &v.tb),
Bound::Excluded(id) => thing::new(opt.ns()?, opt.db()?, &v.tb, id).encode().unwrap(),
Bound::Included(id) => {
let mut key = thing::new(opt.ns(), opt.db(), &v.tb, id).encode().unwrap();
let mut key = thing::new(opt.ns()?, opt.db()?, &v.tb, id).encode().unwrap();
key.push(0x00);
key
}
Expand Down Expand Up @@ -429,8 +429,8 @@ impl<'a> Processor<'a> {
e: Edges,
) -> Result<(), Error> {
// Pull out options
let ns = opt.ns();
let db = opt.db();
let ns = opt.ns()?;
let db = opt.db()?;
let tb = &e.from.tb;
let id = &e.from.id;
// Fetch start and end key pairs
Expand Down Expand Up @@ -522,7 +522,7 @@ impl<'a> Processor<'a> {
// Parse the data from the store
let gra: graph::Graph = graph::Graph::decode(&k)?;
// Fetch the data from the store
let key = thing::new(opt.ns(), opt.db(), gra.ft, &gra.fk);
let key = thing::new(opt.ns()?, opt.db()?, gra.ft, &gra.fk);
let val = ctx.tx_lock().await.get(key).await?;
let rid = Thing::from((gra.ft, gra.fk));
// Parse the data from the store
Expand Down Expand Up @@ -555,7 +555,7 @@ impl<'a> Processor<'a> {
irf: IteratorRef,
) -> Result<(), Error> {
// Check that the table exists
ctx.tx_lock().await.check_ns_db_tb(opt.ns(), opt.db(), &table.0, opt.strict).await?;
ctx.tx_lock().await.check_ns_db_tb(opt.ns()?, opt.db()?, &table.0, opt.strict).await?;
if let Some(exe) = ctx.get_query_executor() {
if let Some(mut iterator) = exe.new_iterator(opt, irf).await? {
// Get the first batch
Expand Down Expand Up @@ -623,7 +623,7 @@ impl Iterable {
thg: &Thing,
) -> Result<Value, Error> {
// Fetch the data from the store
let key = thing::new(opt.ns(), opt.db(), &thg.tb, &thg.id);
let key = thing::new(opt.ns()?, opt.db()?, &thg.tb, &thg.id);
// Fetch and parse the data from the store
let val = tx.get(key).await?.map(Value::from).unwrap_or(Value::None);
// Return the result
Expand Down
2 changes: 1 addition & 1 deletion core/src/doc/allow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ impl<'a> Document<'a> {
// Check if this record exists
if self.id.is_some() {
// Should we run permissions checks?
if opt.check_perms(stm.into()) {
if opt.check_perms(stm.into())? {
// Get the table
let tb = self.tb(ctx, opt).await?;
// Get the permission clause
Expand Down
6 changes: 3 additions & 3 deletions core/src/doc/changefeeds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,16 @@ impl<'a> Document<'a> {
// Claim transaction
let mut run = ctx.tx_lock().await;
// Get the database and the table for the record
let db = run.add_and_cache_db(opt.ns(), opt.db(), opt.strict).await?;
let db = run.add_and_cache_db(opt.ns()?, opt.db()?, opt.strict).await?;
// Check if changefeeds are enabled
if let Some(cf) = db.as_ref().changefeed.as_ref().or(tb.as_ref().changefeed.as_ref()) {
// Get the arguments
let tb = tb.name.as_str();
let id = self.id.as_ref().unwrap();
// Create the changefeed entry
run.record_change(
opt.ns(),
opt.db(),
opt.ns()?,
opt.db()?,
tb,
id,
self.initial.doc.clone(),
Expand Down
2 changes: 1 addition & 1 deletion core/src/doc/compute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ impl<'a> Document<'a> {
// we load the new record, and reprocess
Err(Error::RetryWithId(v)) => {
// Fetch the data from the store
let key = crate::key::thing::new(opt.ns(), opt.db(), &v.tb, &v.id);
let key = crate::key::thing::new(opt.ns()?, opt.db()?, &v.tb, &v.id);
let val = ctx.tx_lock().await.get(key).await?;
// Parse the data from the store
let val = match val {
Expand Down
18 changes: 9 additions & 9 deletions core/src/doc/document.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ impl<'a> Document<'a> {
// Get the record id
let rid = self.id.as_ref().unwrap();
// Get the table definition
let tb = run.get_and_cache_tb(opt.ns(), opt.db(), &rid.tb).await;
let tb = run.get_and_cache_tb(opt.ns()?, opt.db()?, &rid.tb).await;
// Return the table or attempt to define it
match tb {
// The table doesn't exist
Expand All @@ -162,9 +162,9 @@ impl<'a> Document<'a> {
// Allowed to run?
opt.is_allowed(Action::Edit, ResourceKind::Table, &Base::Db)?;
// We can create the table automatically
run.add_and_cache_ns(opt.ns(), opt.strict).await?;
run.add_and_cache_db(opt.ns(), opt.db(), opt.strict).await?;
run.add_and_cache_tb(opt.ns(), opt.db(), &rid.tb, opt.strict).await
run.add_and_cache_ns(opt.ns()?, opt.strict).await?;
run.add_and_cache_db(opt.ns()?, opt.db()?, opt.strict).await?;
run.add_and_cache_tb(opt.ns()?, opt.db()?, &rid.tb, opt.strict).await
}
// There was an error
Err(err) => Err(err),
Expand All @@ -181,7 +181,7 @@ impl<'a> Document<'a> {
// Get the record id
let id = self.id.as_ref().unwrap();
// Get the table definitions
ctx.tx_lock().await.all_tb_views(opt.ns(), opt.db(), &id.tb).await
ctx.tx_lock().await.all_tb_views(opt.ns()?, opt.db()?, &id.tb).await
}
/// Get the events for this document
pub async fn ev(
Expand All @@ -192,7 +192,7 @@ impl<'a> Document<'a> {
// Get the record id
let id = self.id.as_ref().unwrap();
// Get the event definitions
ctx.tx_lock().await.all_tb_events(opt.ns(), opt.db(), &id.tb).await
ctx.tx_lock().await.all_tb_events(opt.ns()?, opt.db()?, &id.tb).await
}
/// Get the fields for this document
pub async fn fd(
Expand All @@ -203,7 +203,7 @@ impl<'a> Document<'a> {
// Get the record id
let id = self.id.as_ref().unwrap();
// Get the field definitions
ctx.tx_lock().await.all_tb_fields(opt.ns(), opt.db(), &id.tb).await
ctx.tx_lock().await.all_tb_fields(opt.ns()?, opt.db()?, &id.tb).await
}
/// Get the indexes for this document
pub async fn ix(
Expand All @@ -214,7 +214,7 @@ impl<'a> Document<'a> {
// Get the record id
let id = self.id.as_ref().unwrap();
// Get the index definitions
ctx.tx_lock().await.all_tb_indexes(opt.ns(), opt.db(), &id.tb).await
ctx.tx_lock().await.all_tb_indexes(opt.ns()?, opt.db()?, &id.tb).await
}
// Get the lives for this document
pub async fn lv(
Expand All @@ -225,6 +225,6 @@ impl<'a> Document<'a> {
// Get the record id
let id = self.id.as_ref().unwrap();
// Get the table definition
ctx.tx_lock().await.all_tb_lives(opt.ns(), opt.db(), &id.tb).await
ctx.tx_lock().await.all_tb_lives(opt.ns()?, opt.db()?, &id.tb).await
}
}
8 changes: 4 additions & 4 deletions core/src/doc/edges.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,16 +30,16 @@ impl<'a> Document<'a> {
// Get temporary edge references
let (ref o, ref i) = (Dir::Out, Dir::In);
// Store the left pointer edge
let key = crate::key::graph::new(opt.ns(), opt.db(), &l.tb, &l.id, o, rid);
let key = crate::key::graph::new(opt.ns()?, opt.db()?, &l.tb, &l.id, o, rid);
run.set(key, vec![]).await?;
// Store the left inner edge
let key = crate::key::graph::new(opt.ns(), opt.db(), &rid.tb, &rid.id, i, l);
let key = crate::key::graph::new(opt.ns()?, opt.db()?, &rid.tb, &rid.id, i, l);
run.set(key, vec![]).await?;
// Store the right inner edge
let key = crate::key::graph::new(opt.ns(), opt.db(), &rid.tb, &rid.id, o, r);
let key = crate::key::graph::new(opt.ns()?, opt.db()?, &rid.tb, &rid.id, o, r);
run.set(key, vec![]).await?;
// Store the right pointer edge
let key = crate::key::graph::new(opt.ns(), opt.db(), &r.tb, &r.id, i, rid);
let key = crate::key::graph::new(opt.ns()?, opt.db()?, &r.tb, &r.id, i, rid);
run.set(key, vec![]).await?;
// Store the edges on the record
self.current.doc.to_mut().put(&*EDGE, Value::Bool(true));
Expand Down
2 changes: 1 addition & 1 deletion core/src/doc/field.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ impl<'a> Document<'a> {
}
}
// Check for a PERMISSIONS clause
if opt.check_perms(Action::Edit) {
if opt.check_perms(Action::Edit)? {
// Get the permission clause
let perms = if self.is_new() {
&fd.permissions.create
Expand Down

0 comments on commit d9ae887

Please sign in to comment.