Make auth errors generic over protocol

next
Sayan Nandan 2 years ago
parent 89067c1fd5
commit 31bdc83108
No known key found for this signature in database
GPG Key ID: 8BC07A0A4D41DD52

@ -65,6 +65,16 @@ pub enum ActionError {
IoError(std::io::Error),
}
impl PartialEq for ActionError {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::ActionError(a1), Self::ActionError(a2)) => a1 == a2,
(Self::IoError(ioe1), Self::IoError(ioe2)) => ioe1.to_string() == ioe2.to_string(),
_ => false,
}
}
}
impl From<&'static [u8]> for ActionError {
fn from(e: &'static [u8]) -> Self {
Self::ActionError(e)
@ -79,23 +89,26 @@ impl From<IoError> for ActionError {
#[cold]
#[inline(never)]
fn map_ddl_error_to_status<P: ProtocolSpec>(e: DdlError) -> ActionError {
let r = match e {
DdlError::AlreadyExists => P::RSTRING_ALREADY_EXISTS,
DdlError::DdlTransactionFailure => P::RSTRING_DDL_TRANSACTIONAL_FAILURE,
DdlError::DefaultNotFound => P::RSTRING_DEFAULT_UNSET,
DdlError::NotEmpty => P::RSTRING_KEYSPACE_NOT_EMPTY,
DdlError::NotReady => P::RSTRING_NOT_READY,
DdlError::ObjectNotFound => P::RSTRING_CONTAINER_NOT_FOUND,
DdlError::ProtectedObject => P::RSTRING_PROTECTED_OBJECT,
DdlError::StillInUse => P::RSTRING_STILL_IN_USE,
DdlError::WrongModel => P::RSTRING_WRONG_MODEL,
};
ActionError::ActionError(r)
}
#[inline(always)]
pub fn translate_ddl_error<P: ProtocolSpec, T>(r: Result<T, DdlError>) -> Result<T, ActionError> {
match r {
Ok(r) => Ok(r),
Err(e) => {
let err = match e {
DdlError::AlreadyExists => P::RSTRING_ALREADY_EXISTS,
DdlError::DdlTransactionFailure => P::RSTRING_DDL_TRANSACTIONAL_FAILURE,
DdlError::DefaultNotFound => P::RSTRING_DEFAULT_UNSET,
DdlError::NotEmpty => P::RSTRING_KEYSPACE_NOT_EMPTY,
DdlError::NotReady => P::RSTRING_NOT_READY,
DdlError::ObjectNotFound => P::RSTRING_CONTAINER_NOT_FOUND,
DdlError::ProtectedObject => P::RSTRING_PROTECTED_OBJECT,
DdlError::StillInUse => P::RSTRING_STILL_IN_USE,
DdlError::WrongModel => P::RSTRING_WRONG_MODEL,
};
Err(ActionError::ActionError(err))
}
Err(e) => Err(map_ddl_error_to_status::<P>(e)),
}
}

@ -1,70 +0,0 @@
/*
* Created on Sun Mar 06 2022
*
* This file is a part of Skytable
* Skytable (formerly known as TerrabaseDB or Skybase) is a free and open-source
* NoSQL database written by Sayan Nandan ("the Author") with the
* vision to provide flexibility in data modelling without compromising
* on performance, queryability or scalability.
*
* Copyright (c) 2022, Sayan Nandan <ohsayan@outlook.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
use crate::actions::ActionError;
/// Skyhash respstring: already claimed (user was already claimed)
pub const AUTH_ERROR_ALREADYCLAIMED: &[u8] = b"!err-auth-already-claimed\n";
/// Skyhash respcode(10): bad credentials (either bad creds or invalid user)
pub const AUTH_CODE_BAD_CREDENTIALS: &[u8] = b"!10\n";
/// Skyhash respstring: auth is disabled
pub const AUTH_ERROR_DISABLED: &[u8] = b"!err-auth-disabled\n";
/// Skyhash respcode(11): Insufficient permissions (same for anonymous user)
pub const AUTH_CODE_PERMS: &[u8] = b"!11\n";
/// Skyhash respstring: ID is too long
pub const AUTH_ERROR_ILLEGAL_USERNAME: &[u8] = b"!err-auth-illegal-username\n";
/// Skyhash respstring: ID is protected/in use
pub const AUTH_ERROR_FAILED_TO_DELETE_USER: &[u8] = b"!err-auth-deluser-fail\n";
/// Auth erros
#[derive(PartialEq, Debug)]
pub enum AuthError {
/// The auth slot was already claimed
AlreadyClaimed,
/// Bad userid/tokens/keys
BadCredentials,
/// Auth is disabled
Disabled,
/// The action is not available to the current account
PermissionDenied,
/// The user is anonymous and doesn't have the right to execute this
Anonymous,
/// Some other error
Other(&'static [u8]),
}
impl From<AuthError> for ActionError {
fn from(e: AuthError) -> Self {
let r = match e {
AuthError::AlreadyClaimed => AUTH_ERROR_ALREADYCLAIMED,
AuthError::Anonymous | AuthError::PermissionDenied => AUTH_CODE_PERMS,
AuthError::BadCredentials => AUTH_CODE_BAD_CREDENTIALS,
AuthError::Disabled => AUTH_ERROR_DISABLED,
AuthError::Other(e) => e,
};
ActionError::ActionError(r)
}
}

@ -38,9 +38,7 @@
mod keys;
pub mod provider;
pub use provider::{AuthProvider, AuthResult, Authmap};
pub mod errors;
pub use errors::AuthError;
pub use provider::{AuthProvider, Authmap};
#[cfg(test)]
mod tests;
@ -70,20 +68,20 @@ action! {
AUTH_ADDUSER => {
ensure_boolean_or_aerr::<P>(iter.len() == 1)?; // just the username
let username = unsafe { iter.next_unchecked() };
let key = auth.provider_mut().claim_user(username)?;
let key = auth.provider_mut().claim_user::<P>(username)?;
con.write_string(&key).await?;
Ok(())
}
AUTH_LOGOUT => {
ensure_boolean_or_aerr::<P>(iter.is_empty())?; // nothing else
auth.provider_mut().logout()?;
auth.provider_mut().logout::<P>()?;
auth.swap_executor_to_anonymous();
con._write_raw(P::RCODE_OKAY).await?;
Ok(())
}
AUTH_DELUSER => {
ensure_boolean_or_aerr::<P>(iter.len() == 1)?; // just the username
auth.provider_mut().delete_user(unsafe { iter.next_unchecked() })?;
auth.provider_mut().delete_user::<P>(unsafe { iter.next_unchecked() })?;
con._write_raw(P::RCODE_OKAY).await?;
Ok(())
}
@ -95,12 +93,12 @@ action! {
}
fn auth_whoami(con: &mut T, auth: &mut AuthProviderHandle<'_, P, T, Strm>, iter: &mut ActionIter<'_>) {
ensure_boolean_or_aerr::<P>(ActionIter::is_empty(iter))?;
con.write_string(&auth.provider().whoami()?).await?;
con.write_string(&auth.provider().whoami::<P>()?).await?;
Ok(())
}
fn auth_listuser(con: &mut T, auth: &mut AuthProviderHandle<'_, P, T, Strm>, iter: &mut ActionIter<'_>) {
ensure_boolean_or_aerr::<P>(ActionIter::is_empty(iter))?;
let usernames = auth.provider().collect_usernames()?;
let usernames = auth.provider().collect_usernames::<P>()?;
con.write_typed_non_null_array_header(usernames.len(), b'+').await?;
for username in usernames {
con.write_typed_non_null_array_element(username.as_bytes()).await?;
@ -111,13 +109,15 @@ action! {
let newkey = match iter.len() {
1 => {
// so this fella thinks they're root
auth.provider().regenerate(unsafe {iter.next_unchecked()})?
auth.provider().regenerate::<P>(
unsafe { iter.next_unchecked() }
)?
}
2 => {
// so this fella is giving us the origin key
let origin = unsafe { iter.next_unchecked() };
let id = unsafe { iter.next_unchecked() };
auth.provider().regenerate_using_origin(origin, id)?
auth.provider().regenerate_using_origin::<P>(origin, id)?
}
_ => return util::err(P::RCODE_ACTION_ERR),
};
@ -127,7 +127,7 @@ action! {
fn _auth_claim(con: &mut T, auth: &mut AuthProviderHandle<'_, P, T, Strm>, iter: &mut ActionIter<'_>) {
ensure_boolean_or_aerr::<P>(iter.len() == 1)?; // just the origin key
let origin_key = unsafe { iter.next_unchecked() };
let key = auth.provider_mut().claim_root(origin_key)?;
let key = auth.provider_mut().claim_root::<P>(origin_key)?;
auth.swap_executor_to_authenticated();
con.write_string(&key).await?;
Ok(())
@ -144,14 +144,14 @@ action! {
AUTH_CLAIM => self::_auth_claim(con, auth, &mut iter).await,
AUTH_RESTORE => self::auth_restore(con, auth, &mut iter).await,
AUTH_WHOAMI => self::auth_whoami(con, auth, &mut iter).await,
_ => util::err(errors::AUTH_CODE_PERMS),
_ => util::err(P::AUTH_CODE_PERMS),
}
}
fn _auth_login(con: &mut T, auth: &mut AuthProviderHandle<'_, P, T, Strm>, iter: &mut ActionIter<'_>) {
// sweet, where's our username and password
ensure_boolean_or_aerr::<P>(iter.len() == 2)?; // just the uname and pass
let (username, password) = unsafe { (iter.next_unchecked(), iter.next_unchecked()) };
auth.provider_mut().login(username, password)?;
auth.provider_mut().login::<P>(username, password)?;
auth.swap_executor_to_authenticated();
con._write_raw(P::RCODE_OKAY).await?;
Ok(())

@ -24,9 +24,12 @@
*
*/
use super::{errors, keys, AuthError};
use super::keys;
use crate::actions::{ActionError, ActionResult};
use crate::corestore::array::Array;
use crate::corestore::htable::Coremap;
use crate::protocol::interface::ProtocolSpec;
use crate::util::err;
use std::sync::Arc;
// constants
@ -54,8 +57,6 @@ const USER_ROOT: AuthID = unsafe { AuthID::from_const(USER_ROOT_ARRAY, 4) };
type AuthID = Array<u8, AUTHID_SIZE>;
/// An authn key
pub type Authkey = [u8; AUTHKEY_SIZE];
/// Result of an auth operation
pub type AuthResult<T> = Result<T, AuthError>;
/// Authmap
pub type Authmap = Arc<Coremap<AuthID, Authkey>>;
@ -119,8 +120,8 @@ impl AuthProvider {
pub const fn is_enabled(&self) -> bool {
matches!(self.origin, Some(_))
}
pub fn claim_root(&mut self, origin_key: &[u8]) -> AuthResult<String> {
self.verify_origin(origin_key)?;
pub fn claim_root<P: ProtocolSpec>(&mut self, origin_key: &[u8]) -> ActionResult<String> {
self.verify_origin::<P>(origin_key)?;
// the origin key was good, let's try claiming root
let (key, store) = keys::generate_full();
if self.authmap.true_if_insert(USER_ROOT, store) {
@ -128,33 +129,33 @@ impl AuthProvider {
self.whoami = Some(USER_ROOT);
Ok(key)
} else {
Err(AuthError::AlreadyClaimed)
err(P::AUTH_ERROR_ALREADYCLAIMED)
}
}
fn are_you_root(&self) -> AuthResult<bool> {
self.ensure_enabled()?;
fn are_you_root<P: ProtocolSpec>(&self) -> ActionResult<bool> {
self.ensure_enabled::<P>()?;
match self.whoami.as_ref().map(|v| v.eq(&USER_ROOT)) {
Some(v) => Ok(v),
None => Err(AuthError::Anonymous),
None => err(P::AUTH_CODE_PERMS),
}
}
pub fn claim_user(&self, claimant: &[u8]) -> AuthResult<String> {
self.ensure_root()?;
self._claim_user(claimant)
pub fn claim_user<P: ProtocolSpec>(&self, claimant: &[u8]) -> ActionResult<String> {
self.ensure_root::<P>()?;
self._claim_user::<P>(claimant)
}
pub fn _claim_user(&self, claimant: &[u8]) -> AuthResult<String> {
pub fn _claim_user<P: ProtocolSpec>(&self, claimant: &[u8]) -> ActionResult<String> {
let (key, store) = keys::generate_full();
if self
.authmap
.true_if_insert(Self::try_auth_id(claimant)?, store)
.true_if_insert(Self::try_auth_id::<P>(claimant)?, store)
{
Ok(key)
} else {
Err(AuthError::AlreadyClaimed)
err(P::AUTH_ERROR_ALREADYCLAIMED)
}
}
pub fn login(&mut self, account: &[u8], token: &[u8]) -> AuthResult<()> {
self.ensure_enabled()?;
pub fn login<P: ProtocolSpec>(&mut self, account: &[u8], token: &[u8]) -> ActionResult<()> {
self.ensure_enabled::<P>()?;
match self
.authmap
.get(account)
@ -162,84 +163,94 @@ impl AuthProvider {
{
Some(Some(true)) => {
// great, authenticated
self.whoami = Some(Self::try_auth_id(account)?);
self.whoami = Some(Self::try_auth_id::<P>(account)?);
Ok(())
}
_ => {
// either the password was wrong, or the username was wrong
Err(AuthError::BadCredentials)
err(P::AUTH_CODE_BAD_CREDENTIALS)
}
}
}
pub fn regenerate_using_origin(&self, origin: &[u8], account: &[u8]) -> AuthResult<String> {
self.verify_origin(origin)?;
self._regenerate(account)
pub fn regenerate_using_origin<P: ProtocolSpec>(
&self,
origin: &[u8],
account: &[u8],
) -> ActionResult<String> {
self.verify_origin::<P>(origin)?;
self._regenerate::<P>(account)
}
pub fn regenerate(&self, account: &[u8]) -> AuthResult<String> {
self.ensure_root()?;
self._regenerate(account)
pub fn regenerate<P: ProtocolSpec>(&self, account: &[u8]) -> ActionResult<String> {
self.ensure_root::<P>()?;
self._regenerate::<P>(account)
}
/// Regenerate the token for the given user. This returns a new token
fn _regenerate(&self, account: &[u8]) -> AuthResult<String> {
let id = Self::try_auth_id(account)?;
fn _regenerate<P: ProtocolSpec>(&self, account: &[u8]) -> ActionResult<String> {
let id = Self::try_auth_id::<P>(account)?;
let (key, store) = keys::generate_full();
if self.authmap.true_if_update(id, store) {
Ok(key)
} else {
Err(AuthError::BadCredentials)
err(P::AUTH_CODE_BAD_CREDENTIALS)
}
}
fn try_auth_id(authid: &[u8]) -> AuthResult<AuthID> {
fn try_auth_id<P: ProtocolSpec>(authid: &[u8]) -> ActionResult<AuthID> {
if authid.is_ascii() && authid.len() <= AUTHID_SIZE {
Ok(unsafe {
// We just verified the length
AuthID::from_slice(authid)
})
} else {
Err(AuthError::Other(errors::AUTH_ERROR_ILLEGAL_USERNAME))
err(P::AUTH_ERROR_ILLEGAL_USERNAME)
}
}
pub fn logout(&mut self) -> AuthResult<()> {
self.ensure_enabled()?;
self.whoami.take().map(|_| ()).ok_or(AuthError::Anonymous)
pub fn logout<P: ProtocolSpec>(&mut self) -> ActionResult<()> {
self.ensure_enabled::<P>()?;
self.whoami
.take()
.map(|_| ())
.ok_or(ActionError::ActionError(P::AUTH_CODE_PERMS))
}
fn ensure_enabled(&self) -> AuthResult<()> {
self.origin.as_ref().map(|_| ()).ok_or(AuthError::Disabled)
fn ensure_enabled<P: ProtocolSpec>(&self) -> ActionResult<()> {
self.origin
.as_ref()
.map(|_| ())
.ok_or(ActionError::ActionError(P::AUTH_ERROR_DISABLED))
}
pub fn verify_origin(&self, origin: &[u8]) -> AuthResult<()> {
if self.get_origin()?.eq(origin) {
pub fn verify_origin<P: ProtocolSpec>(&self, origin: &[u8]) -> ActionResult<()> {
if self.get_origin::<P>()?.eq(origin) {
Ok(())
} else {
Err(AuthError::BadCredentials)
err(P::AUTH_CODE_BAD_CREDENTIALS)
}
}
fn get_origin(&self) -> AuthResult<&Authkey> {
fn get_origin<P: ProtocolSpec>(&self) -> ActionResult<&Authkey> {
match self.origin.as_ref() {
Some(key) => Ok(key),
None => Err(AuthError::Disabled),
None => err(P::AUTH_ERROR_DISABLED),
}
}
fn ensure_root(&self) -> AuthResult<()> {
if self.are_you_root()? {
fn ensure_root<P: ProtocolSpec>(&self) -> ActionResult<()> {
if self.are_you_root::<P>()? {
Ok(())
} else {
Err(AuthError::PermissionDenied)
err(P::AUTH_CODE_PERMS)
}
}
pub fn delete_user(&self, user: &[u8]) -> AuthResult<()> {
self.ensure_root()?;
pub fn delete_user<P: ProtocolSpec>(&self, user: &[u8]) -> ActionResult<()> {
self.ensure_root::<P>()?;
if user.eq(&USER_ROOT) {
// can't delete root!
Err(AuthError::Other(errors::AUTH_ERROR_FAILED_TO_DELETE_USER))
err(P::AUTH_ERROR_FAILED_TO_DELETE_USER)
} else if self.authmap.true_if_removed(user) {
Ok(())
} else {
Err(AuthError::BadCredentials)
err(P::AUTH_CODE_BAD_CREDENTIALS)
}
}
/// List all the users
pub fn collect_usernames(&self) -> AuthResult<Vec<String>> {
self.ensure_root()?;
pub fn collect_usernames<P: ProtocolSpec>(&self) -> ActionResult<Vec<String>> {
self.ensure_root::<P>()?;
Ok(self
.authmap
.iter()
@ -247,12 +258,12 @@ impl AuthProvider {
.collect())
}
/// Return the AuthID of the current user
pub fn whoami(&self) -> AuthResult<String> {
self.ensure_enabled()?;
pub fn whoami<P: ProtocolSpec>(&self) -> ActionResult<String> {
self.ensure_enabled::<P>()?;
self.whoami
.as_ref()
.map(|v| String::from_utf8_lossy(v).to_string())
.ok_or(AuthError::Anonymous)
.ok_or(ActionError::ActionError(P::AUTH_CODE_PERMS))
}
}

@ -35,77 +35,88 @@ mod keys {
}
mod authn {
use crate::auth::{AuthError, AuthProvider};
use crate::actions::ActionError;
use crate::auth::AuthProvider;
use crate::protocol::{interface::ProtocolSpec, Skyhash2};
const ORIG: &[u8; 40] = b"c4299d190fb9a00626797fcc138c56eae9971664";
#[test]
fn claim_root_okay() {
let mut provider = AuthProvider::new_blank(Some(*ORIG));
let _ = provider.claim_root(ORIG).unwrap();
let _ = provider.claim_root::<Skyhash2>(ORIG).unwrap();
}
#[test]
fn claim_root_wrongkey() {
let mut provider = AuthProvider::new_blank(Some(*ORIG));
let claim_err = provider.claim_root(&ORIG[1..]).unwrap_err();
assert_eq!(claim_err, AuthError::BadCredentials);
let claim_err = provider.claim_root::<Skyhash2>(&ORIG[1..]).unwrap_err();
assert_eq!(
claim_err,
ActionError::ActionError(Skyhash2::AUTH_CODE_BAD_CREDENTIALS)
);
}
#[test]
fn claim_root_disabled() {
let mut provider = AuthProvider::new_disabled();
assert_eq!(
provider.claim_root(b"abcd").unwrap_err(),
AuthError::Disabled
provider.claim_root::<Skyhash2>(b"abcd").unwrap_err(),
ActionError::ActionError(Skyhash2::AUTH_ERROR_DISABLED)
);
}
#[test]
fn claim_root_already_claimed() {
let mut provider = AuthProvider::new_blank(Some(*ORIG));
let _ = provider.claim_root(ORIG).unwrap();
let _ = provider.claim_root::<Skyhash2>(ORIG).unwrap();
assert_eq!(
provider.claim_root(ORIG).unwrap_err(),
AuthError::AlreadyClaimed
provider.claim_root::<Skyhash2>(ORIG).unwrap_err(),
ActionError::ActionError(Skyhash2::AUTH_ERROR_ALREADYCLAIMED)
);
}
#[test]
fn claim_user_okay_with_login() {
let mut provider = AuthProvider::new_blank(Some(*ORIG));
// claim root
let rootkey = provider.claim_root(ORIG).unwrap();
let rootkey = provider.claim_root::<Skyhash2>(ORIG).unwrap();
// login as root
provider.login(b"root", rootkey.as_bytes()).unwrap();
provider
.login::<Skyhash2>(b"root", rootkey.as_bytes())
.unwrap();
// claim user
let _ = provider.claim_user(b"sayan").unwrap();
let _ = provider.claim_user::<Skyhash2>(b"sayan").unwrap();
}
#[test]
fn claim_user_fail_not_root_with_login() {
let mut provider = AuthProvider::new_blank(Some(*ORIG));
// claim root
let rootkey = provider.claim_root(ORIG).unwrap();
let rootkey = provider.claim_root::<Skyhash2>(ORIG).unwrap();
// login as root
provider.login(b"root", rootkey.as_bytes()).unwrap();
provider
.login::<Skyhash2>(b"root", rootkey.as_bytes())
.unwrap();
// claim user
let userkey = provider.claim_user(b"user").unwrap();
let userkey = provider.claim_user::<Skyhash2>(b"user").unwrap();
// login as user
provider.login(b"user", userkey.as_bytes()).unwrap();
provider
.login::<Skyhash2>(b"user", userkey.as_bytes())
.unwrap();
// now try to claim an user being a non-root account
assert_eq!(
provider.claim_user(b"otheruser").unwrap_err(),
AuthError::PermissionDenied
provider.claim_user::<Skyhash2>(b"otheruser").unwrap_err(),
ActionError::ActionError(Skyhash2::AUTH_CODE_PERMS)
);
}
#[test]
fn claim_user_fail_anonymous() {
let mut provider = AuthProvider::new_blank(Some(*ORIG));
// claim root
let _ = provider.claim_root(ORIG).unwrap();
let _ = provider.claim_root::<Skyhash2>(ORIG).unwrap();
// logout
provider.logout().unwrap();
provider.logout::<Skyhash2>().unwrap();
// try to claim as an anonymous user
assert_eq!(
provider.claim_user(b"newuser").unwrap_err(),
AuthError::Anonymous
provider.claim_user::<Skyhash2>(b"newuser").unwrap_err(),
ActionError::ActionError(Skyhash2::AUTH_CODE_PERMS)
);
}
}

@ -37,7 +37,7 @@
use crate::{
actions::{ActionError, ActionResult},
auth::{self, AuthProvider},
auth::AuthProvider,
corestore::Corestore,
dbnet::{
connection::prelude::FutureResult,
@ -312,8 +312,7 @@ where
}
Query::Pipelined(_) => {
con.write_simple_query_header().await?;
con._write_raw(auth::errors::AUTH_CODE_BAD_CREDENTIALS)
.await?;
con._write_raw(P::AUTH_CODE_BAD_CREDENTIALS).await?;
}
}
Ok(())

@ -52,7 +52,10 @@ These distinctions reduce the likelihood of making mistakes while implementing t
-- Sayan (May, 2022)
*/
pub trait ProtocolSpec {
/// The `ProtocolSpec` trait is used to define the character set and pre-generated elements
/// and responses for a protocol version. To make any actual use of it, you need to implement
/// both the `ProtocolRead` and `ProtocolWrite` for the protocol
pub trait ProtocolSpec: Send + Sync {
// spec information
/// The Skyhash protocol version
@ -61,91 +64,160 @@ pub trait ProtocolSpec {
const PROTOCOL_VERSIONSTRING: &'static str;
// type symbols
/// Type symbol for unicode strings
const TSYMBOL_STRING: u8;
/// Type symbol for blobs
const TSYMBOL_BINARY: u8;
/// Type symbol for float
const TSYMBOL_FLOAT: u8;
/// Type symbok for int64
const TSYMBOL_INT64: u8;
/// Type symbol for typed array
const TSYMBOL_TYPED_ARRAY: u8;
/// Type symbol for typed non-null array
const TSYMBOL_TYPED_NON_NULL_ARRAY: u8;
/// Type symbol for an array
const TSYMBOL_ARRAY: u8;
/// Type symbol for a flat array
const TSYMBOL_FLAT_ARRAY: u8;
// charset
/// The line-feed character or separator
const LF: u8 = b'\n';
// metaframe
/// The header for simple queries
const SIMPLE_QUERY_HEADER: &'static [u8];
/// The header for pipelined queries (excluding length, obviously)
const PIPELINED_QUERY_FIRST_BYTE: u8;
// typed array
/// Null element represenation for a typed array
const TYPE_TYPED_ARRAY_ELEMENT_NULL: &'static [u8];
// respcodes
/// Respcode 0: Okay
const RCODE_OKAY: &'static [u8];
/// Respcode 1: Nil
const RCODE_NIL: &'static [u8];
/// Respcode 2: Overwrite error
const RCODE_OVERWRITE_ERR: &'static [u8];
/// Respcode 3: Action error
const RCODE_ACTION_ERR: &'static [u8];
/// Respcode 4: Packet error
const RCODE_PACKET_ERR: &'static [u8];
/// Respcode 5: Server error
const RCODE_SERVER_ERR: &'static [u8];
/// Respcode 6: Other error
const RCODE_OTHER_ERR_EMPTY: &'static [u8];
/// Respcode 7: Unknown action
const RCODE_UNKNOWN_ACTION: &'static [u8];
/// Respcode 8: Wrongtype error
const RCODE_WRONGTYPE_ERR: &'static [u8];
/// Respcode 9: Unknown data type error
const RCODE_UNKNOWN_DATA_TYPE: &'static [u8];
/// Respcode 10: Encoding error
const RCODE_ENCODING_ERROR: &'static [u8];
// respstrings
/// Respstring when snapshot engine is busy
const RSTRING_SNAPSHOT_BUSY: &'static [u8];
/// Respstring when snapshots are disabled
const RSTRING_SNAPSHOT_DISABLED: &'static [u8];
/// Respstring when duplicate snapshot creation is attempted
const RSTRING_SNAPSHOT_DUPLICATE: &'static [u8];
/// Respstring when snapshot has illegal chars
const RSTRING_SNAPSHOT_ILLEGAL_NAME: &'static [u8];
/// Respstring when a **very bad error** happens (use after termsig)
const RSTRING_ERR_ACCESS_AFTER_TERMSIG: &'static [u8];
/// Respstring when the default container is unset
const RSTRING_DEFAULT_UNSET: &'static [u8];
/// Respstring when the container is not found
const RSTRING_CONTAINER_NOT_FOUND: &'static [u8];
/// Respstring when the container is still in use, but a _free_ op is attempted
const RSTRING_STILL_IN_USE: &'static [u8];
/// Respstring when a protected container is attempted to be accessed/modified
const RSTRING_PROTECTED_OBJECT: &'static [u8];
/// Respstring when an action is not suitable for the current table model
const RSTRING_WRONG_MODEL: &'static [u8];
/// Respstring when the container already exists
const RSTRING_ALREADY_EXISTS: &'static [u8];
/// Respstring when the container is not ready
const RSTRING_NOT_READY: &'static [u8];
/// Respstring when a DDL transaction fails
const RSTRING_DDL_TRANSACTIONAL_FAILURE: &'static [u8];
/// Respstring when an unknow DDL query is run (`CREATE BLAH`, for example)
const RSTRING_UNKNOWN_DDL_QUERY: &'static [u8];
/// Respstring when a bad DDL expression is run
const RSTRING_BAD_EXPRESSION: &'static [u8];
/// Respstring when an unsupported model is attempted to be used during table creation
const RSTRING_UNKNOWN_MODEL: &'static [u8];
/// Respstring when too many arguments are passed to a DDL query
const RSTRING_TOO_MANY_ARGUMENTS: &'static [u8];
/// Respstring when the container name is too long
const RSTRING_CONTAINER_NAME_TOO_LONG: &'static [u8];
/// Respstring when the container name
const RSTRING_BAD_CONTAINER_NAME: &'static [u8];
/// Respstring when an unknown inspect query is run (`INSPECT blah`, for example)
const RSTRING_UNKNOWN_INSPECT_QUERY: &'static [u8];
/// Respstring when an unknown table property is passed during table creation
const RSTRING_UNKNOWN_PROPERTY: &'static [u8];
/// Respstring when a non-empty keyspace is attempted to be dropped
const RSTRING_KEYSPACE_NOT_EMPTY: &'static [u8];
/// Respstring when a bad type is provided for a key in the K/V engine (like using a `list`
/// for the key)
const RSTRING_BAD_TYPE_FOR_KEY: &'static [u8];
/// Respstring when a non-existent index is attempted to be accessed in a list
const RSTRING_LISTMAP_BAD_INDEX: &'static [u8];
/// Respstring when a list is empty and we attempt to access/modify it
const RSTRING_LISTMAP_LIST_IS_EMPTY: &'static [u8];
// element responses
/// A string element containing the text "HEY!"
const ELEMRESP_HEYA: &'static [u8];
// full responses
/// A **full response** for a packet error
const FULLRESP_RCODE_PACKET_ERR: &'static [u8];
/// A **full response** for a wrongtype error
const FULLRESP_RCODE_WRONG_TYPE: &'static [u8];
// LUTs
/// A LUT for SET operations
const SET_NLUT: BytesNicheLUT = BytesNicheLUT::new(
Self::RCODE_ENCODING_ERROR,
Self::RCODE_OKAY,
Self::RCODE_OVERWRITE_ERR,
);
/// A LUT for lists
const OKAY_BADIDX_NIL_NLUT: BytesNicheLUT = BytesNicheLUT::new(
Self::RCODE_NIL,
Self::RCODE_OKAY,
Self::RSTRING_LISTMAP_BAD_INDEX,
);
/// A LUT for SET operations
const OKAY_OVW_BLUT: BytesBoolTable =
BytesBoolTable::new(Self::RCODE_OKAY, Self::RCODE_OVERWRITE_ERR);
/// A LUT for UPDATE operations
const UPDATE_NLUT: BytesNicheLUT = BytesNicheLUT::new(
Self::RCODE_ENCODING_ERROR,
Self::RCODE_OKAY,
Self::RCODE_NIL,
);
// auth error respstrings
/// respstring: already claimed (user was already claimed)
const AUTH_ERROR_ALREADYCLAIMED: &'static [u8];
/// respcode(10): bad credentials (either bad creds or invalid user)
const AUTH_CODE_BAD_CREDENTIALS: &'static [u8];
/// respstring: auth is disabled
const AUTH_ERROR_DISABLED: &'static [u8];
/// respcode(11): Insufficient permissions (same for anonymous user)
const AUTH_CODE_PERMS: &'static [u8];
/// respstring: ID is too long
const AUTH_ERROR_ILLEGAL_USERNAME: &'static [u8];
/// respstring: ID is protected/in use
const AUTH_ERROR_FAILED_TO_DELETE_USER: &'static [u8];
}
/// # The `ProtocolRead` trait
@ -298,17 +370,7 @@ where
where
'life0: 'ret_life,
'life1: 'ret_life,
Self: Send + 'ret_life,
{
Box::pin(async move {
let stream = self.get_mut_stream();
// <tsymbol><length><lf>
stream.write_all(&[tsymbol]).await?;
stream.write_all(&Integer64::from(data.len())).await?;
stream.write_all(&[P::LF]).await?;
stream.write_all(data).await
})
}
Self: Send + 'ret_life;
/// serialize and write an `&str` to the stream
fn write_string<'life0, 'life1, 'ret_life>(
&'life0 mut self,

@ -55,89 +55,52 @@ impl ProtocolSpec for Skyhash1 {
const TSYMBOL_FLAT_ARRAY: u8 = b'_';
// typed array
const TYPE_TYPED_ARRAY_ELEMENT_NULL: &'static [u8] = b"\0\n";
const TYPE_TYPED_ARRAY_ELEMENT_NULL: &'static [u8] = b"\0";
// metaframe
const SIMPLE_QUERY_HEADER: &'static [u8] = b"*1\n";
const PIPELINED_QUERY_FIRST_BYTE: u8 = b'*';
const SIMPLE_QUERY_HEADER: &'static [u8] = b"*";
const PIPELINED_QUERY_FIRST_BYTE: u8 = b'$';
// respcodes
/// Response code 0 as a array element
const RCODE_OKAY: &'static [u8] = eresp!("0");
/// Response code 1 as a array element
const RCODE_NIL: &'static [u8] = eresp!("1");
/// Response code 2 as a array element
const RCODE_OVERWRITE_ERR: &'static [u8] = eresp!("2");
/// Response code 3 as a array element
const RCODE_ACTION_ERR: &'static [u8] = eresp!("3");
/// Response code 4 as a array element
const RCODE_PACKET_ERR: &'static [u8] = eresp!("4");
/// Response code 5 as a array element
const RCODE_SERVER_ERR: &'static [u8] = eresp!("5");
/// Response code 6 as a array element
const RCODE_OTHER_ERR_EMPTY: &'static [u8] = eresp!("6");
/// "Unknown action" error response
const RCODE_UNKNOWN_ACTION: &'static [u8] = eresp!("Unknown action");
/// Response code 7
const RCODE_WRONGTYPE_ERR: &'static [u8] = eresp!("7");
/// Response code 8
const RCODE_UNKNOWN_DATA_TYPE: &'static [u8] = eresp!("8");
/// Response code 9 as an array element
const RCODE_ENCODING_ERROR: &'static [u8] = eresp!("9");
// respstrings
/// Snapshot busy error
const RSTRING_SNAPSHOT_BUSY: &'static [u8] = eresp!("err-snapshot-busy");
/// Snapshot disabled (other error)
const RSTRING_SNAPSHOT_DISABLED: &'static [u8] = eresp!("err-snapshot-disabled");
/// Duplicate snapshot
const RSTRING_SNAPSHOT_DUPLICATE: &'static [u8] = eresp!("duplicate-snapshot");
/// Snapshot has illegal name (other error)
const RSTRING_SNAPSHOT_ILLEGAL_NAME: &'static [u8] = eresp!("err-invalid-snapshot-name");
/// Access after termination signal (other error)
const RSTRING_ERR_ACCESS_AFTER_TERMSIG: &'static [u8] = eresp!("err-access-after-termsig");
// keyspace related resps
/// The default container was not set
const RSTRING_DEFAULT_UNSET: &'static [u8] = eresp!("default-container-unset");
/// The container was not found
const RSTRING_CONTAINER_NOT_FOUND: &'static [u8] = eresp!("container-not-found");
/// The container is still in use and so cannot be removed
const RSTRING_STILL_IN_USE: &'static [u8] = eresp!("still-in-use");
/// This is a protected object and hence cannot be accessed
const RSTRING_PROTECTED_OBJECT: &'static [u8] = eresp!("err-protected-object");
/// The action was applied against the wrong model
const RSTRING_WRONG_MODEL: &'static [u8] = eresp!("wrong-model");
/// The container already exists
const RSTRING_ALREADY_EXISTS: &'static [u8] = eresp!("err-already-exists");
/// The container is not ready
const RSTRING_NOT_READY: &'static [u8] = eresp!("not-ready");
/// A transactional failure occurred
const RSTRING_DDL_TRANSACTIONAL_FAILURE: &'static [u8] = eresp!("transactional-failure");
/// An unknown DDL query was run
const RSTRING_UNKNOWN_DDL_QUERY: &'static [u8] = eresp!("unknown-ddl-query");
/// The expression for a DDL query was malformed
const RSTRING_BAD_EXPRESSION: &'static [u8] = eresp!("malformed-expression");
/// An unknown model was passed in a DDL query
const RSTRING_UNKNOWN_MODEL: &'static [u8] = eresp!("unknown-model");
/// Too many arguments were passed to model constructor
const RSTRING_TOO_MANY_ARGUMENTS: &'static [u8] = eresp!("too-many-args");
/// The container name is too long
const RSTRING_CONTAINER_NAME_TOO_LONG: &'static [u8] = eresp!("container-name-too-long");
/// The container name contains invalid characters
const RSTRING_BAD_CONTAINER_NAME: &'static [u8] = eresp!("bad-container-name");
/// An unknown inspect query
const RSTRING_UNKNOWN_INSPECT_QUERY: &'static [u8] = eresp!("unknown-inspect-query");
/// An unknown table property was passed
const RSTRING_UNKNOWN_PROPERTY: &'static [u8] = eresp!("unknown-property");
/// The keyspace is not empty and hence cannot be removed
const RSTRING_KEYSPACE_NOT_EMPTY: &'static [u8] = eresp!("keyspace-not-empty");
/// Bad type supplied in a DDL query for the key
const RSTRING_BAD_TYPE_FOR_KEY: &'static [u8] = eresp!("bad-type-for-key");
/// The index for the provided list was non-existent
const RSTRING_LISTMAP_BAD_INDEX: &'static [u8] = eresp!("bad-list-index");
/// The list is empty
const RSTRING_LISTMAP_LIST_IS_EMPTY: &'static [u8] = eresp!("list-is-empty");
// elements
@ -146,6 +109,14 @@ impl ProtocolSpec for Skyhash1 {
// full responses
const FULLRESP_RCODE_PACKET_ERR: &'static [u8] = b"*1\n!1\n4\n";
const FULLRESP_RCODE_WRONG_TYPE: &'static [u8] = b"*1\n!1\n7\n";
// auth rcodes/strings
const AUTH_ERROR_ALREADYCLAIMED: &'static [u8] = eresp!("err-auth-already-claimed");
const AUTH_CODE_BAD_CREDENTIALS: &'static [u8] = eresp!("10");
const AUTH_ERROR_DISABLED: &'static [u8] = eresp!("err-auth-disabled");
const AUTH_CODE_PERMS: &'static [u8] = eresp!("11");
const AUTH_ERROR_ILLEGAL_USERNAME: &'static [u8] = eresp!("err-auth-illegal-username");
const AUTH_ERROR_FAILED_TO_DELETE_USER: &'static [u8] = eresp!("err-auth-deluser-fail");
}
impl<Strm, T> ProtocolRead<Skyhash1, Strm> for T
@ -163,6 +134,27 @@ where
T: RawConnection<Skyhash1, Strm> + Send + Sync,
Strm: Stream,
{
fn write_mono_length_prefixed_with_tsymbol<'life0, 'life1, 'ret_life>(
&'life0 mut self,
data: &'life1 [u8],
tsymbol: u8,
) -> FutureResult<'ret_life, IoResult<()>>
where
'life0: 'ret_life,
'life1: 'ret_life,
Self: Send + 'ret_life,
{
Box::pin(async move {
let stream = self.get_mut_stream();
// <tsymbol><length><lf>
stream.write_all(&[tsymbol]).await?;
stream.write_all(&Integer64::from(data.len())).await?;
stream.write_all(&[Skyhash1::LF]).await?;
// <data><lf>
stream.write_all(data).await?;
stream.write_all(&[Skyhash1::LF]).await
})
}
fn write_string<'life0, 'life1, 'ret_life>(
&'life0 mut self,
string: &'life1 str,

@ -60,82 +60,45 @@ impl ProtocolSpec for Skyhash2 {
const PIPELINED_QUERY_FIRST_BYTE: u8 = b'$';
// respcodes
/// Response code 0 as a array element
const RCODE_OKAY: &'static [u8] = eresp!("0");
/// Response code 1 as a array element
const RCODE_NIL: &'static [u8] = eresp!("1");
/// Response code 2 as a array element
const RCODE_OVERWRITE_ERR: &'static [u8] = eresp!("2");
/// Response code 3 as a array element
const RCODE_ACTION_ERR: &'static [u8] = eresp!("3");
/// Response code 4 as a array element
const RCODE_PACKET_ERR: &'static [u8] = eresp!("4");
/// Response code 5 as a array element
const RCODE_SERVER_ERR: &'static [u8] = eresp!("5");
/// Response code 6 as a array element
const RCODE_OTHER_ERR_EMPTY: &'static [u8] = eresp!("6");
/// "Unknown action" error response
const RCODE_UNKNOWN_ACTION: &'static [u8] = eresp!("Unknown action");
/// Response code 7
const RCODE_WRONGTYPE_ERR: &'static [u8] = eresp!("7");
/// Response code 8
const RCODE_UNKNOWN_DATA_TYPE: &'static [u8] = eresp!("8");
/// Response code 9 as an array element
const RCODE_ENCODING_ERROR: &'static [u8] = eresp!("9");
// respstrings
/// Snapshot busy error
const RSTRING_SNAPSHOT_BUSY: &'static [u8] = eresp!("err-snapshot-busy");
/// Snapshot disabled (other error)
const RSTRING_SNAPSHOT_DISABLED: &'static [u8] = eresp!("err-snapshot-disabled");
/// Duplicate snapshot
const RSTRING_SNAPSHOT_DUPLICATE: &'static [u8] = eresp!("duplicate-snapshot");
/// Snapshot has illegal name (other error)
const RSTRING_SNAPSHOT_ILLEGAL_NAME: &'static [u8] = eresp!("err-invalid-snapshot-name");
/// Access after termination signal (other error)
const RSTRING_ERR_ACCESS_AFTER_TERMSIG: &'static [u8] = eresp!("err-access-after-termsig");
// keyspace related resps
/// The default container was not set
const RSTRING_DEFAULT_UNSET: &'static [u8] = eresp!("default-container-unset");
/// The container was not found
const RSTRING_CONTAINER_NOT_FOUND: &'static [u8] = eresp!("container-not-found");
/// The container is still in use and so cannot be removed
const RSTRING_STILL_IN_USE: &'static [u8] = eresp!("still-in-use");
/// This is a protected object and hence cannot be accessed
const RSTRING_PROTECTED_OBJECT: &'static [u8] = eresp!("err-protected-object");
/// The action was applied against the wrong model
const RSTRING_WRONG_MODEL: &'static [u8] = eresp!("wrong-model");
/// The container already exists
const RSTRING_ALREADY_EXISTS: &'static [u8] = eresp!("err-already-exists");
/// The container is not ready
const RSTRING_NOT_READY: &'static [u8] = eresp!("not-ready");
/// A transactional failure occurred
const RSTRING_DDL_TRANSACTIONAL_FAILURE: &'static [u8] = eresp!("transactional-failure");
/// An unknown DDL query was run
const RSTRING_UNKNOWN_DDL_QUERY: &'static [u8] = eresp!("unknown-ddl-query");
/// The expression for a DDL query was malformed
const RSTRING_BAD_EXPRESSION: &'static [u8] = eresp!("malformed-expression");
/// An unknown model was passed in a DDL query
const RSTRING_UNKNOWN_MODEL: &'static [u8] = eresp!("unknown-model");
/// Too many arguments were passed to model constructor
const RSTRING_TOO_MANY_ARGUMENTS: &'static [u8] = eresp!("too-many-args");
/// The container name is too long
const RSTRING_CONTAINER_NAME_TOO_LONG: &'static [u8] = eresp!("container-name-too-long");
/// The container name contains invalid characters
const RSTRING_BAD_CONTAINER_NAME: &'static [u8] = eresp!("bad-container-name");
/// An unknown inspect query
const RSTRING_UNKNOWN_INSPECT_QUERY: &'static [u8] = eresp!("unknown-inspect-query");
/// An unknown table property was passed
const RSTRING_UNKNOWN_PROPERTY: &'static [u8] = eresp!("unknown-property");
/// The keyspace is not empty and hence cannot be removed
const RSTRING_KEYSPACE_NOT_EMPTY: &'static [u8] = eresp!("keyspace-not-empty");
/// Bad type supplied in a DDL query for the key
const RSTRING_BAD_TYPE_FOR_KEY: &'static [u8] = eresp!("bad-type-for-key");
/// The index for the provided list was non-existent
const RSTRING_LISTMAP_BAD_INDEX: &'static [u8] = eresp!("bad-list-index");
/// The list is empty
const RSTRING_LISTMAP_LIST_IS_EMPTY: &'static [u8] = eresp!("list-is-empty");
// elements
@ -144,6 +107,14 @@ impl ProtocolSpec for Skyhash2 {
// full responses
const FULLRESP_RCODE_PACKET_ERR: &'static [u8] = b"*!4\n";
const FULLRESP_RCODE_WRONG_TYPE: &'static [u8] = b"*!7\n";
// auth respcodes/strings
const AUTH_ERROR_ALREADYCLAIMED: &'static [u8] = eresp!("err-auth-already-claimed");
const AUTH_CODE_BAD_CREDENTIALS: &'static [u8] = eresp!("10");
const AUTH_ERROR_DISABLED: &'static [u8] = eresp!("err-auth-disabled");
const AUTH_CODE_PERMS: &'static [u8] = eresp!("11");
const AUTH_ERROR_ILLEGAL_USERNAME: &'static [u8] = eresp!("err-auth-illegal-username");
const AUTH_ERROR_FAILED_TO_DELETE_USER: &'static [u8] = eresp!("err-auth-deluser-fail");
}
impl<Strm, T> ProtocolRead<Skyhash2, Strm> for T
@ -161,6 +132,25 @@ where
T: RawConnection<Skyhash2, Strm> + Send + Sync,
Strm: Stream,
{
fn write_mono_length_prefixed_with_tsymbol<'life0, 'life1, 'ret_life>(
&'life0 mut self,
data: &'life1 [u8],
tsymbol: u8,
) -> FutureResult<'ret_life, IoResult<()>>
where
'life0: 'ret_life,
'life1: 'ret_life,
Self: Send + 'ret_life,
{
Box::pin(async move {
let stream = self.get_mut_stream();
// <tsymbol><length><lf>
stream.write_all(&[tsymbol]).await?;
stream.write_all(&Integer64::from(data.len())).await?;
stream.write_all(&[Skyhash2::LF]).await?;
stream.write_all(data).await
})
}
fn write_string<'life0, 'life1, 'ret_life>(
&'life0 mut self,
string: &'life1 str,

@ -89,7 +89,7 @@ action! {
};
match iter.next_lowercase().unwrap_or_custom_aerr(P::RCODE_PACKET_ERR)?.as_ref() {
ACTION_AUTH => auth::auth_login_only(con, auth, iter).await,
_ => util::err(auth::errors::AUTH_CODE_BAD_CREDENTIALS),
_ => util::err(P::AUTH_CODE_BAD_CREDENTIALS),
}
}
//// Execute a simple query

Loading…
Cancel
Save