Implement scope signup and signin functionality
This commit is contained in:
parent
b93b87f2a1
commit
eff4d2c5e9
9 changed files with 462 additions and 34 deletions
4
Cargo.lock
generated
4
Cargo.lock
generated
|
@ -1355,9 +1355,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "jsonwebtoken"
|
||||
version = "8.1.0"
|
||||
version = "8.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cc9051c17f81bae79440afa041b3a278e1de71bfb96d32454b477fd4703ccb6f"
|
||||
checksum = "1aa4b4af834c6cfd35d8763d359661b90f2e45d8f750a0849156c7f4671af09c"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"pem",
|
||||
|
|
|
@ -25,7 +25,7 @@ fern = { version = "0.6.1", features = ["colored"] }
|
|||
futures = "0.3.21"
|
||||
http = "0.2.8"
|
||||
hyper = "0.14.19"
|
||||
jsonwebtoken = "8.1.0"
|
||||
jsonwebtoken = "8.1.1"
|
||||
log = "0.4.17"
|
||||
once_cell = "1.12.0"
|
||||
rand = "0.8.5"
|
||||
|
|
|
@ -25,15 +25,58 @@ pub struct Session {
|
|||
}
|
||||
|
||||
impl Session {
|
||||
// Retrieves the selected namespace
|
||||
/// Create a session with root authentication
|
||||
pub fn for_kv() -> Session {
|
||||
Session {
|
||||
au: Arc::new(Auth::Kv),
|
||||
..Session::default()
|
||||
}
|
||||
}
|
||||
/// Create a session with namespace authentication
|
||||
pub fn for_ns<S>(ns: S) -> Session
|
||||
where
|
||||
S: Into<String> + Clone,
|
||||
{
|
||||
Session {
|
||||
ns: Some(ns.clone().into()),
|
||||
au: Arc::new(Auth::Ns(ns.into())),
|
||||
..Session::default()
|
||||
}
|
||||
}
|
||||
/// Create a session with database authentication
|
||||
pub fn for_db<S>(ns: S, db: S) -> Session
|
||||
where
|
||||
S: Into<String> + Clone,
|
||||
{
|
||||
Session {
|
||||
ns: Some(ns.clone().into()),
|
||||
db: Some(db.clone().into()),
|
||||
au: Arc::new(Auth::Db(ns.into(), db.into())),
|
||||
..Session::default()
|
||||
}
|
||||
}
|
||||
/// Create a session with scope authentication
|
||||
pub fn for_sc<S>(ns: S, db: S, sc: S) -> Session
|
||||
where
|
||||
S: Into<String> + Clone,
|
||||
{
|
||||
Session {
|
||||
ns: Some(ns.clone().into()),
|
||||
db: Some(db.clone().into()),
|
||||
sc: Some(sc.clone().into()),
|
||||
au: Arc::new(Auth::Sc(ns.into(), db.into(), sc.into())),
|
||||
..Session::default()
|
||||
}
|
||||
}
|
||||
/// Retrieves the selected namespace
|
||||
pub(crate) fn ns(&self) -> Option<Arc<String>> {
|
||||
self.ns.to_owned().map(Arc::new)
|
||||
}
|
||||
// Retrieves the selected database
|
||||
/// Retrieves the selected database
|
||||
pub(crate) fn db(&self) -> Option<Arc<String>> {
|
||||
self.db.to_owned().map(Arc::new)
|
||||
}
|
||||
// Convert a session into a runtime
|
||||
/// Convert a session into a runtime
|
||||
pub(crate) fn context<'a>(&self, mut ctx: Context<'a>) -> Context<'a> {
|
||||
// Add scope value
|
||||
let key = String::from("scope");
|
||||
|
|
|
@ -758,6 +758,26 @@ impl Value {
|
|||
}
|
||||
}
|
||||
|
||||
// -----------------------------------
|
||||
// Record ID extraction
|
||||
// -----------------------------------
|
||||
|
||||
/// Fetch the record id if there is one
|
||||
pub fn rid(self) -> Option<Thing> {
|
||||
match self {
|
||||
Value::Object(mut v) => match v.remove("id") {
|
||||
Some(Value::Thing(v)) => Some(v),
|
||||
_ => None,
|
||||
},
|
||||
Value::Array(mut v) => match v.len() {
|
||||
1 => v.remove(0).rid(),
|
||||
_ => None,
|
||||
},
|
||||
Value::Thing(v) => Some(v),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------
|
||||
// JSON Path conversion
|
||||
// -----------------------------------
|
||||
|
|
23
src/net/jwt.rs
Normal file
23
src/net/jwt.rs
Normal file
|
@ -0,0 +1,23 @@
|
|||
use jsonwebtoken::{Algorithm, Header};
|
||||
use once_cell::sync::Lazy;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
pub static HEADER: Lazy<Header> = Lazy::new(|| Header::new(Algorithm::HS512));
|
||||
|
||||
#[derive(Debug, Default, Serialize, Deserialize)]
|
||||
pub struct Claims {
|
||||
pub iat: i64,
|
||||
pub nbf: i64,
|
||||
pub exp: i64,
|
||||
pub iss: String,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub ns: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub db: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub sc: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub tk: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub id: Option<String>,
|
||||
}
|
|
@ -4,6 +4,7 @@ mod fail;
|
|||
mod head;
|
||||
mod import;
|
||||
mod index;
|
||||
mod jwt;
|
||||
mod key;
|
||||
mod log;
|
||||
mod output;
|
||||
|
|
|
@ -1,15 +1,14 @@
|
|||
use crate::err::Error;
|
||||
use crate::net::jwt::Claims;
|
||||
use crate::net::CF;
|
||||
use crate::net::DB;
|
||||
use argon2::password_hash::{PasswordHash, PasswordVerifier};
|
||||
use argon2::Argon2;
|
||||
use jsonwebtoken::{decode, DecodingKey, Validation};
|
||||
use once_cell::sync::Lazy;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::net::SocketAddr;
|
||||
use std::sync::Arc;
|
||||
use surrealdb::sql::Algorithm;
|
||||
use surrealdb::sql::Thing;
|
||||
use surrealdb::sql::Value;
|
||||
use surrealdb::Auth;
|
||||
use surrealdb::Session;
|
||||
|
@ -75,20 +74,6 @@ fn config(algo: Algorithm, code: String) -> Result<(DecodingKey, Validation), Er
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct Claims {
|
||||
iss: String,
|
||||
iat: usize,
|
||||
nbf: usize,
|
||||
exp: usize,
|
||||
ns: Option<String>,
|
||||
db: Option<String>,
|
||||
sc: Option<String>,
|
||||
tk: Option<String>,
|
||||
tb: Option<String>,
|
||||
id: Option<String>,
|
||||
}
|
||||
|
||||
static KEY: Lazy<DecodingKey> = Lazy::new(|| DecodingKey::from_secret(&[]));
|
||||
|
||||
static DUD: Lazy<Validation> = Lazy::new(|| {
|
||||
|
@ -215,12 +200,13 @@ async fn token(auth: String, mut session: Session) -> Result<Session, Error> {
|
|||
db: Some(db),
|
||||
sc: Some(sc),
|
||||
tk: Some(tk),
|
||||
tb: Some(tb),
|
||||
id: Some(id),
|
||||
..
|
||||
} => {
|
||||
// Create a new readonly transaction
|
||||
let mut tx = kvs.transaction(false, false).await?;
|
||||
// Parse the record id
|
||||
let id = surrealdb::sql::thing(&id)?;
|
||||
// Get the scope token
|
||||
let de = tx.get_st(&ns, &db, &sc, &tk).await?;
|
||||
let cf = config(de.kind, de.code)?;
|
||||
|
@ -230,7 +216,7 @@ async fn token(auth: String, mut session: Session) -> Result<Session, Error> {
|
|||
session.ns = Some(ns.to_owned());
|
||||
session.db = Some(db.to_owned());
|
||||
session.sc = Some(sc.to_owned());
|
||||
session.sd = Some(Value::from(Thing::from((tb, id))));
|
||||
session.sd = Some(Value::from(id));
|
||||
session.au = Arc::new(Auth::Sc(ns, db, sc));
|
||||
return Ok(session);
|
||||
}
|
||||
|
@ -239,12 +225,13 @@ async fn token(auth: String, mut session: Session) -> Result<Session, Error> {
|
|||
ns: Some(ns),
|
||||
db: Some(db),
|
||||
sc: Some(sc),
|
||||
tb: Some(tb),
|
||||
id: Some(id),
|
||||
..
|
||||
} => {
|
||||
// Create a new readonly transaction
|
||||
let mut tx = kvs.transaction(false, false).await?;
|
||||
// Parse the record id
|
||||
let id = surrealdb::sql::thing(&id)?;
|
||||
// Get the scope
|
||||
let de = tx.get_sc(&ns, &db, &sc).await?;
|
||||
let cf = config(Algorithm::Hs512, de.code)?;
|
||||
|
@ -254,7 +241,7 @@ async fn token(auth: String, mut session: Session) -> Result<Session, Error> {
|
|||
session.ns = Some(ns.to_owned());
|
||||
session.db = Some(db.to_owned());
|
||||
session.sc = Some(sc.to_owned());
|
||||
session.sd = Some(Value::from(Thing::from((tb, id))));
|
||||
session.sd = Some(Value::from(id));
|
||||
session.au = Arc::new(Auth::Sc(ns, db, sc));
|
||||
return Ok(session);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,18 @@
|
|||
use crate::cnf::SERVER_NAME;
|
||||
use crate::err::Error;
|
||||
use crate::net::head;
|
||||
use warp::http;
|
||||
use crate::net::jwt::{Claims, HEADER};
|
||||
use crate::net::DB;
|
||||
use argon2::password_hash::{PasswordHash, PasswordVerifier};
|
||||
use argon2::Argon2;
|
||||
use bytes::Bytes;
|
||||
use chrono::{Duration, Utc};
|
||||
use jsonwebtoken::{encode, EncodingKey};
|
||||
use std::str;
|
||||
use surrealdb::sql::Object;
|
||||
use surrealdb::sql::Value;
|
||||
use surrealdb::Session;
|
||||
use warp::http::Response;
|
||||
use warp::Filter;
|
||||
|
||||
const MAX: u64 = 1024; // 1 KiB
|
||||
|
@ -10,11 +23,243 @@ pub fn config() -> impl Filter<Extract = impl warp::Reply, Error = warp::Rejecti
|
|||
// Set opts method
|
||||
let opts = base.and(warp::options()).map(warp::reply);
|
||||
// Set post method
|
||||
let post = base.and(warp::post()).and(warp::body::content_length_limit(MAX)).and_then(handler);
|
||||
let post = base
|
||||
.and(warp::post())
|
||||
.and(warp::body::content_length_limit(MAX))
|
||||
.and(warp::body::bytes())
|
||||
.and_then(handler);
|
||||
// Specify route
|
||||
opts.or(post).with(head::cors())
|
||||
}
|
||||
|
||||
async fn handler() -> Result<impl warp::Reply, warp::Rejection> {
|
||||
Ok(warp::reply::with_status("Ok", http::StatusCode::OK))
|
||||
async fn handler(body: Bytes) -> Result<impl warp::Reply, warp::Rejection> {
|
||||
//
|
||||
let data = str::from_utf8(&body).unwrap();
|
||||
//
|
||||
match surrealdb::sql::json(data) {
|
||||
// The provided value was an object
|
||||
Ok(Value::Object(vars)) => {
|
||||
// Parse the speficied variables
|
||||
let ns = vars.get("NS").or_else(|| vars.get("ns"));
|
||||
let db = vars.get("DB").or_else(|| vars.get("db"));
|
||||
let sc = vars.get("SC").or_else(|| vars.get("sc"));
|
||||
// Match the authentication type
|
||||
match (ns, db, sc) {
|
||||
(Some(ns), Some(db), Some(sc)) => {
|
||||
// Process the provided values
|
||||
let ns = ns.to_strand().as_string();
|
||||
let db = db.to_strand().as_string();
|
||||
let sc = sc.to_strand().as_string();
|
||||
// Attempt to signin to specified scope
|
||||
match signin_sc(ns, db, sc, vars).await {
|
||||
// Namespace authentication was successful
|
||||
Ok(v) => Ok(Response::builder().body(v)),
|
||||
// There was an error with authentication
|
||||
Err(e) => Err(warp::reject::custom(e)),
|
||||
}
|
||||
}
|
||||
(Some(ns), Some(db), None) => {
|
||||
// Get the provided user and pass
|
||||
let user = vars.get("user");
|
||||
let pass = vars.get("pass");
|
||||
// Validate the user and pass
|
||||
match (user, pass) {
|
||||
// There is a username and password
|
||||
(Some(user), Some(pass)) => {
|
||||
// Process the provided values
|
||||
let ns = ns.to_strand().as_string();
|
||||
let db = db.to_strand().as_string();
|
||||
let user = user.to_strand().as_string();
|
||||
let pass = pass.to_strand().as_string();
|
||||
// Attempt to signin to database
|
||||
match signin_db(ns, db, user, pass).await {
|
||||
// Namespace authentication was successful
|
||||
Ok(v) => Ok(Response::builder().body(v)),
|
||||
// There was an error with authentication
|
||||
Err(e) => Err(warp::reject::custom(e)),
|
||||
}
|
||||
}
|
||||
// There is no username or password
|
||||
_ => Err(warp::reject::custom(Error::InvalidAuth)),
|
||||
}
|
||||
}
|
||||
(Some(ns), None, None) => {
|
||||
// Get the provided user and pass
|
||||
let user = vars.get("user");
|
||||
let pass = vars.get("pass");
|
||||
// Validate the user and pass
|
||||
match (user, pass) {
|
||||
// There is a username and password
|
||||
(Some(user), Some(pass)) => {
|
||||
// Process the provided values
|
||||
let ns = ns.to_strand().as_string();
|
||||
let user = user.to_strand().as_string();
|
||||
let pass = pass.to_strand().as_string();
|
||||
// Attempt to signin to namespace
|
||||
match signin_ns(ns, user, pass).await {
|
||||
// Namespace authentication was successful
|
||||
Ok(v) => Ok(Response::builder().body(v)),
|
||||
// There was an error with authentication
|
||||
Err(e) => Err(warp::reject::custom(e)),
|
||||
}
|
||||
}
|
||||
// There is no username or password
|
||||
_ => Err(warp::reject::custom(Error::InvalidAuth)),
|
||||
}
|
||||
}
|
||||
// No NS, DB, or SC keys were specified
|
||||
_ => Err(warp::reject::custom(Error::InvalidAuth)),
|
||||
}
|
||||
}
|
||||
// The provided value was not an object
|
||||
_ => Err(warp::reject::custom(Error::Request)),
|
||||
}
|
||||
}
|
||||
|
||||
async fn signin_sc(ns: String, db: String, sc: String, vars: Object) -> Result<String, Error> {
|
||||
// Get a database reference
|
||||
let kvs = DB.get().unwrap();
|
||||
// Create a new readonly transaction
|
||||
let mut tx = kvs.transaction(false, false).await?;
|
||||
// Check if the supplied NS Login exists
|
||||
match tx.get_sc(&ns, &db, &sc).await {
|
||||
Ok(sv) => {
|
||||
match sv.signin {
|
||||
// This scope allows signin
|
||||
Some(val) => {
|
||||
// Setup the query params
|
||||
let vars = Some(vars.0);
|
||||
// Setup the query session
|
||||
let sess = Session::for_db(&ns, &db);
|
||||
// Compute the value with the params
|
||||
match kvs.compute(val, &sess, vars).await {
|
||||
// The signin value succeeded
|
||||
Ok(val) => match val.rid() {
|
||||
// There is a record returned
|
||||
Some(rid) => {
|
||||
// Create the authentication key
|
||||
let key = EncodingKey::from_secret(sv.code.as_ref());
|
||||
// Create the authentication claim
|
||||
let val = Claims {
|
||||
iss: SERVER_NAME.to_owned(),
|
||||
iat: Utc::now().timestamp(),
|
||||
nbf: Utc::now().timestamp(),
|
||||
exp: match sv.session {
|
||||
Some(v) => Utc::now() + Duration::from_std(v.0).unwrap(),
|
||||
_ => Utc::now() + Duration::hours(1),
|
||||
}
|
||||
.timestamp(),
|
||||
ns: Some(ns),
|
||||
db: Some(db),
|
||||
sc: Some(sc),
|
||||
id: Some(rid.to_raw()),
|
||||
..Claims::default()
|
||||
};
|
||||
// Create the authentication token
|
||||
match encode(&*HEADER, &val, &key) {
|
||||
// The auth token was created successfully
|
||||
Ok(tk) => Ok(tk),
|
||||
// There was an error creating the token
|
||||
_ => Err(Error::InvalidAuth),
|
||||
}
|
||||
}
|
||||
// No record was returned
|
||||
_ => Err(Error::InvalidAuth),
|
||||
},
|
||||
// The signin query failed
|
||||
_ => Err(Error::InvalidAuth),
|
||||
}
|
||||
}
|
||||
// This scope does not allow signin
|
||||
_ => Err(Error::InvalidAuth),
|
||||
}
|
||||
}
|
||||
// The scope does not exists
|
||||
_ => Err(Error::InvalidAuth),
|
||||
}
|
||||
}
|
||||
|
||||
async fn signin_db(ns: String, db: String, user: String, pass: String) -> Result<String, Error> {
|
||||
// Get a database reference
|
||||
let kvs = DB.get().unwrap();
|
||||
// Create a new readonly transaction
|
||||
let mut tx = kvs.transaction(false, false).await?;
|
||||
// Check if the supplied DB Login exists
|
||||
match tx.get_dl(&ns, &db, &user).await {
|
||||
Ok(dl) => {
|
||||
// Compute the hash and verify the password
|
||||
let hash = PasswordHash::new(&dl.hash).unwrap();
|
||||
// Attempt to verify the password using Argon2
|
||||
match Argon2::default().verify_password(pass.as_ref(), &hash) {
|
||||
Ok(_) => {
|
||||
// Create the authentication key
|
||||
let key = EncodingKey::from_secret(dl.code.as_ref());
|
||||
// Create the authentication claim
|
||||
let val = Claims {
|
||||
iss: SERVER_NAME.to_owned(),
|
||||
iat: Utc::now().timestamp(),
|
||||
nbf: Utc::now().timestamp(),
|
||||
exp: (Utc::now() + Duration::hours(1)).timestamp(),
|
||||
ns: Some(ns),
|
||||
db: Some(db),
|
||||
id: Some(user),
|
||||
..Claims::default()
|
||||
};
|
||||
// Create the authentication token
|
||||
match encode(&*HEADER, &val, &key) {
|
||||
// The auth token was created successfully
|
||||
Ok(tk) => Ok(tk),
|
||||
// There was an error creating the token
|
||||
_ => Err(Error::InvalidAuth),
|
||||
}
|
||||
}
|
||||
// The password did not verify
|
||||
_ => Err(Error::InvalidAuth),
|
||||
}
|
||||
}
|
||||
// The specified user login does not exist
|
||||
_ => Err(Error::InvalidAuth),
|
||||
}
|
||||
}
|
||||
|
||||
async fn signin_ns(ns: String, user: String, pass: String) -> Result<String, Error> {
|
||||
// Get a database reference
|
||||
let kvs = DB.get().unwrap();
|
||||
// Create a new readonly transaction
|
||||
let mut tx = kvs.transaction(false, false).await?;
|
||||
// Check if the supplied NS Login exists
|
||||
match tx.get_nl(&ns, &user).await {
|
||||
Ok(nl) => {
|
||||
// Compute the hash and verify the password
|
||||
let hash = PasswordHash::new(&nl.hash).unwrap();
|
||||
// Attempt to verify the password using Argon2
|
||||
match Argon2::default().verify_password(pass.as_ref(), &hash) {
|
||||
Ok(_) => {
|
||||
// Create the authentication key
|
||||
let key = EncodingKey::from_secret(nl.code.as_ref());
|
||||
// Create the authentication claim
|
||||
let val = Claims {
|
||||
iss: SERVER_NAME.to_owned(),
|
||||
iat: Utc::now().timestamp(),
|
||||
nbf: Utc::now().timestamp(),
|
||||
exp: (Utc::now() + Duration::hours(1)).timestamp(),
|
||||
ns: Some(ns),
|
||||
id: Some(user),
|
||||
..Claims::default()
|
||||
};
|
||||
// Create the authentication token
|
||||
match encode(&*HEADER, &val, &key) {
|
||||
// The auth token was created successfully
|
||||
Ok(tk) => Ok(tk),
|
||||
// There was an error creating the token
|
||||
_ => Err(Error::InvalidAuth),
|
||||
}
|
||||
}
|
||||
// The password did not verify
|
||||
_ => Err(Error::InvalidAuth),
|
||||
}
|
||||
}
|
||||
// The specified user login does not exist
|
||||
_ => Err(Error::InvalidAuth),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,16 @@
|
|||
use crate::cnf::SERVER_NAME;
|
||||
use crate::err::Error;
|
||||
use crate::net::head;
|
||||
use warp::http;
|
||||
use crate::net::jwt::{Claims, HEADER};
|
||||
use crate::net::DB;
|
||||
use bytes::Bytes;
|
||||
use chrono::{Duration, Utc};
|
||||
use jsonwebtoken::{encode, EncodingKey};
|
||||
use std::str;
|
||||
use surrealdb::sql::Object;
|
||||
use surrealdb::sql::Value;
|
||||
use surrealdb::Session;
|
||||
use warp::http::Response;
|
||||
use warp::Filter;
|
||||
|
||||
const MAX: u64 = 1024; // 1 KiB
|
||||
|
@ -10,11 +21,109 @@ pub fn config() -> impl Filter<Extract = impl warp::Reply, Error = warp::Rejecti
|
|||
// Set opts method
|
||||
let opts = base.and(warp::options()).map(warp::reply);
|
||||
// Set post method
|
||||
let post = base.and(warp::post()).and(warp::body::content_length_limit(MAX)).and_then(handler);
|
||||
let post = base
|
||||
.and(warp::post())
|
||||
.and(warp::body::content_length_limit(MAX))
|
||||
.and(warp::body::bytes())
|
||||
.and_then(handler);
|
||||
// Specify route
|
||||
opts.or(post).with(head::cors())
|
||||
}
|
||||
|
||||
async fn handler() -> Result<impl warp::Reply, warp::Rejection> {
|
||||
Ok(warp::reply::with_status("Ok", http::StatusCode::OK))
|
||||
async fn handler(body: Bytes) -> Result<impl warp::Reply, warp::Rejection> {
|
||||
//
|
||||
let data = str::from_utf8(&body).unwrap();
|
||||
//
|
||||
match surrealdb::sql::json(data) {
|
||||
// The provided value was an object
|
||||
Ok(Value::Object(vars)) => {
|
||||
// Parse the speficied variables
|
||||
let ns = vars.get("NS").or_else(|| vars.get("ns"));
|
||||
let db = vars.get("DB").or_else(|| vars.get("db"));
|
||||
let sc = vars.get("SC").or_else(|| vars.get("sc"));
|
||||
// Match the authentication type
|
||||
match (ns, db, sc) {
|
||||
(Some(ns), Some(db), Some(sc)) => {
|
||||
// Process the provided values
|
||||
let ns = ns.to_strand().as_string();
|
||||
let db = db.to_strand().as_string();
|
||||
let sc = sc.to_strand().as_string();
|
||||
// Attempt to signin to specified scope
|
||||
match signup_sc(ns, db, sc, vars).await {
|
||||
// Namespace authentication was successful
|
||||
Ok(v) => Ok(Response::builder().body(v)),
|
||||
// There was an error with authentication
|
||||
Err(e) => Err(warp::reject::custom(e)),
|
||||
}
|
||||
}
|
||||
// No NS, DB, or SC keys were specified
|
||||
_ => Err(warp::reject::custom(Error::InvalidAuth)),
|
||||
}
|
||||
}
|
||||
// The provided value was not an object
|
||||
_ => Err(warp::reject::custom(Error::Request)),
|
||||
}
|
||||
}
|
||||
|
||||
async fn signup_sc(ns: String, db: String, sc: String, vars: Object) -> Result<String, Error> {
|
||||
// Get a database reference
|
||||
let kvs = DB.get().unwrap();
|
||||
// Create a new readonly transaction
|
||||
let mut tx = kvs.transaction(false, false).await?;
|
||||
// Check if the supplied NS Login exists
|
||||
match tx.get_sc(&ns, &db, &sc).await {
|
||||
Ok(sv) => {
|
||||
match sv.signup {
|
||||
// This scope allows signin
|
||||
Some(val) => {
|
||||
// Setup the query params
|
||||
let vars = Some(vars.0);
|
||||
// Setup the query session
|
||||
let sess = Session::for_db(&ns, &db);
|
||||
// Compute the value with the params
|
||||
match kvs.compute(val, &sess, vars).await {
|
||||
// The signin value succeeded
|
||||
Ok(val) => match val.rid() {
|
||||
// There is a record returned
|
||||
Some(rid) => {
|
||||
// Create the authentication key
|
||||
let key = EncodingKey::from_secret(sv.code.as_ref());
|
||||
// Create the authentication claim
|
||||
let val = Claims {
|
||||
iss: SERVER_NAME.to_owned(),
|
||||
iat: Utc::now().timestamp(),
|
||||
nbf: Utc::now().timestamp(),
|
||||
exp: match sv.session {
|
||||
Some(v) => Utc::now() + Duration::from_std(v.0).unwrap(),
|
||||
_ => Utc::now() + Duration::hours(1),
|
||||
}
|
||||
.timestamp(),
|
||||
ns: Some(ns),
|
||||
db: Some(db),
|
||||
sc: Some(sc),
|
||||
id: Some(rid.to_raw()),
|
||||
..Claims::default()
|
||||
};
|
||||
// Create the authentication token
|
||||
match encode(&*HEADER, &val, &key) {
|
||||
// The auth token was created successfully
|
||||
Ok(tk) => Ok(tk),
|
||||
// There was an error creating the token
|
||||
_ => Err(Error::InvalidAuth),
|
||||
}
|
||||
}
|
||||
// No record was returned
|
||||
_ => Err(Error::InvalidAuth),
|
||||
},
|
||||
// The signin query failed
|
||||
_ => Err(Error::InvalidAuth),
|
||||
}
|
||||
}
|
||||
// This scope does not allow signin
|
||||
_ => Err(Error::InvalidAuth),
|
||||
}
|
||||
}
|
||||
// The scope does not exists
|
||||
_ => Err(Error::InvalidAuth),
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue