Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
263 changes: 263 additions & 0 deletions libsql/src/auth.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,263 @@
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct AuthContext<'a> {
pub action: AuthAction<'a>,

pub database_name: Option<&'a str>,

pub accessor: Option<&'a str>,
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum AuthAction<'a> {
Unknown {
code: i32,
arg1: Option<&'a str>,
arg2: Option<&'a str>,
},
CreateIndex {
index_name: &'a str,
table_name: &'a str,
},
CreateTable {
table_name: &'a str,
},
CreateTempIndex {
index_name: &'a str,
table_name: &'a str,
},
CreateTempTable {
table_name: &'a str,
},
CreateTempTrigger {
trigger_name: &'a str,
table_name: &'a str,
},
CreateTempView {
view_name: &'a str,
},
CreateTrigger {
trigger_name: &'a str,
table_name: &'a str,
},
CreateView {
view_name: &'a str,
},
Delete {
table_name: &'a str,
},
DropIndex {
index_name: &'a str,
table_name: &'a str,
},
DropTable {
table_name: &'a str,
},
DropTempIndex {
index_name: &'a str,
table_name: &'a str,
},
DropTempTable {
table_name: &'a str,
},
DropTempTrigger {
trigger_name: &'a str,
table_name: &'a str,
},
DropTempView {
view_name: &'a str,
},
DropTrigger {
trigger_name: &'a str,
table_name: &'a str,
},
DropView {
view_name: &'a str,
},
Insert {
table_name: &'a str,
},
Pragma {
pragma_name: &'a str,
pragma_value: Option<&'a str>,
},
Read {
table_name: &'a str,
column_name: &'a str,
},
Select,
Transaction {
operation: TransactionOperation,
},
Update {
table_name: &'a str,
column_name: &'a str,
},
Attach {
filename: &'a str,
},
Detach {
database_name: &'a str,
},
AlterTable {
database_name: &'a str,
table_name: &'a str,
},
Reindex {
index_name: &'a str,
},
Analyze {
table_name: &'a str,
},
CreateVtable {
table_name: &'a str,
module_name: &'a str,
},
DropVtable {
table_name: &'a str,
module_name: &'a str,
},
Function {
function_name: &'a str,
},
Savepoint {
operation: TransactionOperation,
savepoint_name: &'a str,
},
Recursive,
}

#[cfg(feature = "core")]
impl<'a> AuthAction<'a> {
pub(crate) fn from_raw(code: i32, arg1: Option<&'a str>, arg2: Option<&'a str>) -> Self {
use libsql_sys::ffi;

match (code, arg1, arg2) {
(ffi::SQLITE_CREATE_INDEX, Some(index_name), Some(table_name)) => Self::CreateIndex {
index_name,
table_name,
},
(ffi::SQLITE_CREATE_TABLE, Some(table_name), _) => Self::CreateTable { table_name },
(ffi::SQLITE_CREATE_TEMP_INDEX, Some(index_name), Some(table_name)) => {
Self::CreateTempIndex {
index_name,
table_name,
}
}
(ffi::SQLITE_CREATE_TEMP_TABLE, Some(table_name), _) => {
Self::CreateTempTable { table_name }
}
(ffi::SQLITE_CREATE_TEMP_TRIGGER, Some(trigger_name), Some(table_name)) => {
Self::CreateTempTrigger {
trigger_name,
table_name,
}
}
(ffi::SQLITE_CREATE_TEMP_VIEW, Some(view_name), _) => {
Self::CreateTempView { view_name }
}
(ffi::SQLITE_CREATE_TRIGGER, Some(trigger_name), Some(table_name)) => {
Self::CreateTrigger {
trigger_name,
table_name,
}
}
(ffi::SQLITE_CREATE_VIEW, Some(view_name), _) => Self::CreateView { view_name },
(ffi::SQLITE_DELETE, Some(table_name), None) => Self::Delete { table_name },
(ffi::SQLITE_DROP_INDEX, Some(index_name), Some(table_name)) => Self::DropIndex {
index_name,
table_name,
},
(ffi::SQLITE_DROP_TABLE, Some(table_name), _) => Self::DropTable { table_name },
(ffi::SQLITE_DROP_TEMP_INDEX, Some(index_name), Some(table_name)) => {
Self::DropTempIndex {
index_name,
table_name,
}
}
(ffi::SQLITE_DROP_TEMP_TABLE, Some(table_name), _) => {
Self::DropTempTable { table_name }
}
(ffi::SQLITE_DROP_TEMP_TRIGGER, Some(trigger_name), Some(table_name)) => {
Self::DropTempTrigger {
trigger_name,
table_name,
}
}
(ffi::SQLITE_DROP_TEMP_VIEW, Some(view_name), _) => Self::DropTempView { view_name },
(ffi::SQLITE_DROP_TRIGGER, Some(trigger_name), Some(table_name)) => Self::DropTrigger {
trigger_name,
table_name,
},
(ffi::SQLITE_DROP_VIEW, Some(view_name), _) => Self::DropView { view_name },
(ffi::SQLITE_INSERT, Some(table_name), _) => Self::Insert { table_name },
(ffi::SQLITE_PRAGMA, Some(pragma_name), pragma_value) => Self::Pragma {
pragma_name,
pragma_value,
},
(ffi::SQLITE_READ, Some(table_name), Some(column_name)) => Self::Read {
table_name,
column_name,
},
(ffi::SQLITE_SELECT, ..) => Self::Select,
(ffi::SQLITE_TRANSACTION, Some(operation_str), _) => Self::Transaction {
operation: TransactionOperation::from_str(operation_str),
},
(ffi::SQLITE_UPDATE, Some(table_name), Some(column_name)) => Self::Update {
table_name,
column_name,
},
(ffi::SQLITE_ATTACH, Some(filename), _) => Self::Attach { filename },
(ffi::SQLITE_DETACH, Some(database_name), _) => Self::Detach { database_name },
(ffi::SQLITE_ALTER_TABLE, Some(database_name), Some(table_name)) => Self::AlterTable {
database_name,
table_name,
},
(ffi::SQLITE_REINDEX, Some(index_name), _) => Self::Reindex { index_name },
(ffi::SQLITE_ANALYZE, Some(table_name), _) => Self::Analyze { table_name },
(ffi::SQLITE_CREATE_VTABLE, Some(table_name), Some(module_name)) => {
Self::CreateVtable {
table_name,
module_name,
}
}
(ffi::SQLITE_DROP_VTABLE, Some(table_name), Some(module_name)) => Self::DropVtable {
table_name,
module_name,
},
(ffi::SQLITE_FUNCTION, _, Some(function_name)) => Self::Function { function_name },
(ffi::SQLITE_SAVEPOINT, Some(operation_str), Some(savepoint_name)) => Self::Savepoint {
operation: TransactionOperation::from_str(operation_str),
savepoint_name,
},
(ffi::SQLITE_RECURSIVE, ..) => Self::Recursive,
(code, arg1, arg2) => Self::Unknown { code, arg1, arg2 },
}
}
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum TransactionOperation {
Unknown,
Begin,
Release,
Rollback,
}

#[cfg(feature = "core")]
impl TransactionOperation {
fn from_str(op_str: &str) -> Self {
match op_str {
"BEGIN" => Self::Begin,
"RELEASE" => Self::Release,
"ROLLBACK" => Self::Rollback,
_ => Self::Unknown,
}
}
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Authorization {
Allow,
Ignore,
Deny,
}
11 changes: 11 additions & 0 deletions libsql/src/connection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,15 @@ use std::path::Path;
use std::sync::Arc;
use std::time::Duration;

use crate::auth::{AuthContext, Authorization};
use crate::params::{IntoParams, Params};
use crate::rows::Rows;
use crate::statement::Statement;
use crate::transaction::Transaction;
use crate::{Result, TransactionBehavior};

pub type AuthHook = Arc<dyn Fn(&AuthContext) -> Authorization>;

#[async_trait::async_trait]
pub(crate) trait Conn {
async fn execute(&self, sql: &str, params: Params) -> Result<u64>;
Expand Down Expand Up @@ -43,6 +46,10 @@ pub(crate) trait Conn {
fn load_extension(&self, _dylib_path: &Path, _entry_point: Option<&str>) -> Result<()> {
Err(crate::Error::LoadExtensionNotSupported)
}

fn authorizer(&self, _hook: Option<AuthHook>) -> Result<()> {
Err(crate::Error::AuthorizerNotSupported)
}
}

/// A set of rows returned from `execute_batch`/`execute_transactional_batch`. It is essentially
Expand Down Expand Up @@ -258,6 +265,10 @@ impl Connection {
) -> Result<()> {
self.conn.load_extension(dylib_path.as_ref(), entry_point)
}

pub fn authorizer(&self, hook: Option<AuthHook>) -> Result<()> {
self.conn.authorizer(hook)
}
}

impl fmt::Debug for Connection {
Expand Down
2 changes: 2 additions & 0 deletions libsql/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ pub enum Error {
SyncNotSupported(String), // Not in rusqlite
#[error("Loading extension is only supported in local databases.")]
LoadExtensionNotSupported, // Not in rusqlite
#[error("Authorizer is only supported in local databases.")]
AuthorizerNotSupported, // Not in rusqlite
#[error("Column not found: {0}")]
ColumnNotFound(i32), // Not in rusqlite
#[error("Hrana: `{0}`")]
Expand Down
4 changes: 3 additions & 1 deletion libsql/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ pub use errors::Error;

pub use params::params_from_iter;

mod auth;
mod connection;
mod database;
mod load_extension_guard;
Expand All @@ -176,7 +177,8 @@ cfg_hrana! {
}

pub use self::{
connection::{BatchRows, Connection},
auth::{AuthAction, AuthContext, Authorization},
connection::{AuthHook, BatchRows, Connection},
database::{Builder, Database},
load_extension_guard::LoadExtensionGuard,
rows::{Column, Row, Rows},
Expand Down
Loading
Loading