Compare commits
No commits in common. "2c1c19690f7be12fb1257ea9dfe18672aa98a28e" and "977059c90d3c6836289c14822195c3d38e80b2b9" have entirely different histories.
2c1c19690f
...
977059c90d
14
flake.lock
14
flake.lock
|
@ -33,11 +33,11 @@
|
||||||
},
|
},
|
||||||
"nixpkgs_22_05": {
|
"nixpkgs_22_05": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1668766498,
|
"lastModified": 1668459637,
|
||||||
"narHash": "sha256-UjZlIrbHGlL3H3HZNPTxPSwJfr49jIfbPWCYxk0EQm4=",
|
"narHash": "sha256-HqnWCKujmtu8v0CjzOT0sr7m2AR7+vpbZJOp1R0rodY=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "f42a45c015f28ac3beeb0df360e50cdbf495d44b",
|
"rev": "16f4e04658c2ab10114545af2f39db17d51bd1bd",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -48,11 +48,11 @@
|
||||||
},
|
},
|
||||||
"nixpkgs_unstable": {
|
"nixpkgs_unstable": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1668765800,
|
"lastModified": 1668505710,
|
||||||
"narHash": "sha256-rC40+/W6Hio7b/RsY8SvQPKNx4WqNcTgfYv8cUMAvJk=",
|
"narHash": "sha256-DulcfsGjpSXL9Ma0iQIsb3HRbARCDcA+CNH67pPyMQ0=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "52b2ac8ae18bbad4374ff0dd5aeee0fdf1aea739",
|
"rev": "85d6b3990def7eef45f4502a82496de02a02b6e8",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -67,7 +67,7 @@
|
||||||
"nixpkgs": "nixpkgs"
|
"nixpkgs": "nixpkgs"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"narHash": "sha256-F2ro05D6tGMwSaOYeIediJq6X0ATD7JgWEG2TgOs9Wo=",
|
"narHash": "sha256-WjyKSpFY44ysIHSN3C0L5PKUJuwXDnSg6p5OcYwbZZ4=",
|
||||||
"type": "tarball",
|
"type": "tarball",
|
||||||
"url": "https://github.com/oxalica/rust-overlay/archive/master.tar.gz"
|
"url": "https://github.com/oxalica/rust-overlay/archive/master.tar.gz"
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
use crate::errors::{error, fatal, ok, AppResult, FatalError};
|
use crate::errors::{error, fatal, ok, AppResult};
|
||||||
use rusqlite::types::{FromSql, FromSqlError, FromSqlResult, ValueRef};
|
use rusqlite::types::{FromSql, FromSqlError, FromSqlResult, ValueRef};
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::{convert::Infallible, str::FromStr};
|
use std::{convert::Infallible, str::FromStr};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
@ -9,7 +8,7 @@ use uuid::{adapter::Hyphenated, Uuid};
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
use crate::errors::maybe_fail;
|
use crate::errors::maybe_fail;
|
||||||
|
|
||||||
#[derive(Debug, Error, PartialEq)]
|
#[derive(Debug, Error)]
|
||||||
pub enum AuthenticationError {
|
pub enum AuthenticationError {
|
||||||
#[error("username already exists")]
|
#[error("username already exists")]
|
||||||
DuplicateUsername,
|
DuplicateUsername,
|
||||||
|
@ -21,7 +20,7 @@ pub enum AuthenticationError {
|
||||||
UserNotFound,
|
UserNotFound,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct SessionToken(String);
|
pub struct SessionToken(String);
|
||||||
|
|
||||||
impl From<&str> for SessionToken {
|
impl From<&str> for SessionToken {
|
||||||
|
@ -44,7 +43,7 @@ impl From<SessionToken> for String {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct Invitation(String);
|
pub struct Invitation(String);
|
||||||
|
|
||||||
impl From<&str> for Invitation {
|
impl From<&str> for Invitation {
|
||||||
|
@ -67,7 +66,7 @@ impl From<Invitation> for String {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct UserId(String);
|
pub struct UserId(String);
|
||||||
|
|
||||||
impl From<&str> for UserId {
|
impl From<&str> for UserId {
|
||||||
|
@ -101,7 +100,7 @@ impl FromSql for UserId {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct Username(String);
|
pub struct Username(String);
|
||||||
|
|
||||||
impl From<&str> for Username {
|
impl From<&str> for Username {
|
||||||
|
@ -157,16 +156,11 @@ pub trait AuthenticationDB: Send + Sync {
|
||||||
|
|
||||||
fn delete_user(&mut self, user: UserId) -> AppResult<(), AuthenticationError>;
|
fn delete_user(&mut self, user: UserId) -> AppResult<(), AuthenticationError>;
|
||||||
|
|
||||||
fn validate_session(
|
fn validate_session(&self, session: SessionToken) -> AppResult<(), AuthenticationError>;
|
||||||
&self,
|
|
||||||
session: SessionToken,
|
|
||||||
) -> AppResult<(Username, UserId), AuthenticationError>;
|
|
||||||
|
|
||||||
fn get_userid(&self, username: &Username) -> AppResult<UserId, AuthenticationError>;
|
fn get_user_id(&self, username: Username) -> AppResult<UserId, AuthenticationError>;
|
||||||
|
|
||||||
fn get_username(&self, userid: &UserId) -> AppResult<Username, AuthenticationError>;
|
fn list_users(&self) -> AppResult<Vec<Username>, AuthenticationError>;
|
||||||
|
|
||||||
fn list_users(&self) -> AppResult<Vec<UserId>, AuthenticationError>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
|
@ -267,22 +261,15 @@ impl AuthenticationDB for MemoryAuth {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_session(
|
fn validate_session(&self, session: SessionToken) -> AppResult<(), AuthenticationError> {
|
||||||
&self,
|
if self.sessions.contains_key(&session) {
|
||||||
session: SessionToken,
|
ok(())
|
||||||
) -> AppResult<(Username, UserId), AuthenticationError> {
|
|
||||||
if let Some(userid) = self.sessions.get(&session) {
|
|
||||||
if let Some(username) = self.inverse_users.get(&userid) {
|
|
||||||
ok((username.clone(), userid.clone()))
|
|
||||||
} else {
|
|
||||||
fatal(FatalError::DatabaseInconsistency)
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
error(AuthenticationError::InvalidSession)
|
error::<(), AuthenticationError>(AuthenticationError::InvalidSession)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_userid(&self, username: &Username) -> AppResult<UserId, AuthenticationError> {
|
fn get_user_id(&self, username: Username) -> AppResult<UserId, AuthenticationError> {
|
||||||
Ok(self
|
Ok(self
|
||||||
.users
|
.users
|
||||||
.get(&username)
|
.get(&username)
|
||||||
|
@ -290,99 +277,10 @@ impl AuthenticationDB for MemoryAuth {
|
||||||
.ok_or(AuthenticationError::UserNotFound))
|
.ok_or(AuthenticationError::UserNotFound))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_username(&self, userid: &UserId) -> AppResult<Username, AuthenticationError> {
|
fn list_users(&self) -> AppResult<Vec<Username>, AuthenticationError> {
|
||||||
Ok(self
|
ok(self.users.keys().cloned().collect::<Vec<Username>>())
|
||||||
.inverse_users
|
|
||||||
.get(&userid)
|
|
||||||
.map(|u| u.clone())
|
|
||||||
.ok_or(AuthenticationError::UserNotFound))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn list_users(&self) -> AppResult<Vec<UserId>, AuthenticationError> {
|
|
||||||
ok(self.inverse_users.keys().cloned().collect::<Vec<UserId>>())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {}
|
||||||
use super::*;
|
|
||||||
|
|
||||||
fn with_memory_db<F>(test: F)
|
|
||||||
where
|
|
||||||
F: Fn(Box<dyn AuthenticationDB>),
|
|
||||||
{
|
|
||||||
let authdb: Box<MemoryAuth> = Box::new(Default::default());
|
|
||||||
test(authdb);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn it_can_create_a_user() {
|
|
||||||
fn test_case(mut authdb: Box<dyn AuthenticationDB>) {
|
|
||||||
let username = Username::from("shephard");
|
|
||||||
let userid = authdb
|
|
||||||
.create_user(username.clone())
|
|
||||||
.expect("no fatal errors")
|
|
||||||
.expect("creation should succeed");
|
|
||||||
assert_eq!(authdb.get_userid(&username).unwrap(), Ok(userid.clone()));
|
|
||||||
assert_eq!(authdb.get_username(&userid).unwrap(), Ok(username));
|
|
||||||
assert!(authdb.list_users().unwrap().unwrap().contains(&userid));
|
|
||||||
}
|
|
||||||
with_memory_db(test_case);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn it_does_not_allow_duplicate_users() {
|
|
||||||
fn test_case(mut authdb: Box<dyn AuthenticationDB>) {
|
|
||||||
let username = Username::from("shephard");
|
|
||||||
let _ = authdb
|
|
||||||
.create_user(username.clone())
|
|
||||||
.expect("no fatal errors")
|
|
||||||
.expect("creation should succeed");
|
|
||||||
assert_eq!(
|
|
||||||
authdb.create_user(username.clone()).unwrap(),
|
|
||||||
Err(AuthenticationError::DuplicateUsername)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
with_memory_db(test_case);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn it_allows_multiple_invitations_per_user() {
|
|
||||||
unimplemented!()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn it_exchanges_an_invitation_for_a_session() {
|
|
||||||
unimplemented!()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn it_allows_multiple_sessions_per_user() {
|
|
||||||
unimplemented!()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn it_disallows_invitation_reuse() {
|
|
||||||
unimplemented!()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn it_identifies_a_user_by_session() {
|
|
||||||
unimplemented!()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn it_deletes_a_user_and_invalidates_tokens() {
|
|
||||||
unimplemented!()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn it_deletes_a_session() {
|
|
||||||
unimplemented!()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn it_deletes_an_invitation() {
|
|
||||||
unimplemented!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -5,8 +5,6 @@ use thiserror::Error;
|
||||||
/// down and that the administrator fix a problem.
|
/// down and that the administrator fix a problem.
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum FatalError {
|
pub enum FatalError {
|
||||||
#[error("database is inconsistent")]
|
|
||||||
DatabaseInconsistency,
|
|
||||||
#[error("disk is full")]
|
#[error("disk is full")]
|
||||||
DiskFull,
|
DiskFull,
|
||||||
#[error("io error: {0}")]
|
#[error("io error: {0}")]
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
use errors::{ok, AppResult};
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::{
|
use std::{
|
||||||
net::{IpAddr, Ipv4Addr, SocketAddr},
|
net::{IpAddr, Ipv4Addr, SocketAddr},
|
||||||
|
@ -7,9 +6,7 @@ use std::{
|
||||||
use warp::Filter;
|
use warp::Filter;
|
||||||
|
|
||||||
mod authentication;
|
mod authentication;
|
||||||
use authentication::{
|
use authentication::{AuthenticationDB, AuthenticationError, MemoryAuth, UserId, Username};
|
||||||
AuthenticationDB, AuthenticationError, Invitation, MemoryAuth, SessionToken, UserId, Username,
|
|
||||||
};
|
|
||||||
|
|
||||||
mod database;
|
mod database;
|
||||||
mod errors;
|
mod errors;
|
||||||
|
@ -18,7 +15,7 @@ mod errors;
|
||||||
struct AuthenticationRefused;
|
struct AuthenticationRefused;
|
||||||
impl warp::reject::Reject for AuthenticationRefused {}
|
impl warp::reject::Reject for AuthenticationRefused {}
|
||||||
|
|
||||||
fn with_session(
|
fn with_authentication(
|
||||||
auth_ctx: Arc<RwLock<impl AuthenticationDB>>,
|
auth_ctx: Arc<RwLock<impl AuthenticationDB>>,
|
||||||
) -> impl Filter<Extract = ((Username, UserId),), Error = warp::Rejection> + Clone {
|
) -> impl Filter<Extract = ((Username, UserId),), Error = warp::Rejection> + Clone {
|
||||||
let auth_ctx = auth_ctx.clone();
|
let auth_ctx = auth_ctx.clone();
|
||||||
|
@ -28,11 +25,13 @@ fn with_session(
|
||||||
let auth_ctx = auth_ctx.clone();
|
let auth_ctx = auth_ctx.clone();
|
||||||
async move {
|
async move {
|
||||||
if auth_header.starts_with("Basic ") {
|
if auth_header.starts_with("Basic ") {
|
||||||
let session_token = SessionToken::from(
|
let username = auth_header.split(" ").skip(1).collect::<String>();
|
||||||
auth_header.split(" ").skip(1).collect::<String>().as_str(),
|
match auth_ctx
|
||||||
);
|
.read()
|
||||||
match auth_ctx.read().unwrap().validate_session(session_token) {
|
.unwrap()
|
||||||
Ok(Ok((username, userid))) => Ok((username, userid)),
|
.get_user_id(Username::from(username.as_str()))
|
||||||
|
{
|
||||||
|
Ok(Ok(userid)) => Ok((Username::from(username.as_str()), userid)),
|
||||||
Ok(Err(_)) => Err(warp::reject::custom(AuthenticationRefused)),
|
Ok(Err(_)) => Err(warp::reject::custom(AuthenticationRefused)),
|
||||||
Err(err) => panic!("{}", err),
|
Err(err) => panic!("{}", err),
|
||||||
}
|
}
|
||||||
|
@ -50,13 +49,13 @@ struct ErrorResponse {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
struct MakeUserParams {
|
struct MakeUserParameters {
|
||||||
username: Username,
|
username: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
struct MakeUserResponse {
|
struct MakeUserResponse {
|
||||||
userid: UserId,
|
userid: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_user(
|
fn make_user(
|
||||||
|
@ -65,11 +64,13 @@ fn make_user(
|
||||||
warp::path!("api" / "v1" / "users")
|
warp::path!("api" / "v1" / "users")
|
||||||
.and(warp::put())
|
.and(warp::put())
|
||||||
.and(warp::body::json())
|
.and(warp::body::json())
|
||||||
.map(move |params: MakeUserParams| {
|
.map(move |params: MakeUserParameters| {
|
||||||
let mut auth_ctx = auth_ctx.write().unwrap();
|
let mut auth_ctx = auth_ctx.write().unwrap();
|
||||||
match (*auth_ctx).create_user(Username::from(params.username)) {
|
match (*auth_ctx).create_user(Username::from(params.username.as_str())) {
|
||||||
Ok(Ok(userid)) => warp::reply::json(&MakeUserResponse { userid }),
|
Ok(Ok(userid)) => warp::reply::json(&MakeUserResponse {
|
||||||
Ok(Err(auth_error)) => warp::reply::json(&ErrorResponse {
|
userid: String::from(userid),
|
||||||
|
}),
|
||||||
|
Ok(auth_error) => warp::reply::json(&ErrorResponse {
|
||||||
error: format!("{:?}", auth_error),
|
error: format!("{:?}", auth_error),
|
||||||
}),
|
}),
|
||||||
Err(err) => panic!("{}", err),
|
Err(err) => panic!("{}", err),
|
||||||
|
@ -77,63 +78,6 @@ fn make_user(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
struct MakeInvitationParams {
|
|
||||||
userid: UserId,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize)]
|
|
||||||
struct MakeInvitationResponse {
|
|
||||||
invitation: Invitation,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn make_invitation(
|
|
||||||
auth_ctx: Arc<RwLock<impl AuthenticationDB>>,
|
|
||||||
) -> impl Filter<Extract = impl warp::Reply, Error = warp::Rejection> + Clone {
|
|
||||||
warp::path!("api" / "v1" / "invitations")
|
|
||||||
.and(warp::put())
|
|
||||||
.and(warp::body::json())
|
|
||||||
.map(move |params: MakeInvitationParams| {
|
|
||||||
let mut auth_ctx = auth_ctx.write().unwrap();
|
|
||||||
match (*auth_ctx).create_invitation(params.userid) {
|
|
||||||
Ok(Ok(invitation)) => warp::reply::json(&MakeInvitationResponse { invitation }),
|
|
||||||
Ok(Err(auth_error)) => warp::reply::json(&ErrorResponse {
|
|
||||||
error: format!("{:?}", auth_error),
|
|
||||||
}),
|
|
||||||
Err(err) => panic!("{}", err),
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
struct AuthenticateParams {
|
|
||||||
invitation: Invitation,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize)]
|
|
||||||
struct AuthenticateResponse {
|
|
||||||
session_token: SessionToken,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn authenticate(
|
|
||||||
auth_ctx: Arc<RwLock<impl AuthenticationDB>>,
|
|
||||||
) -> impl Filter<Extract = impl warp::Reply, Error = warp::Rejection> + Clone {
|
|
||||||
warp::path!("api" / "v1" / "authenticate")
|
|
||||||
.and(warp::put())
|
|
||||||
.and(warp::body::json())
|
|
||||||
.map(move |params: AuthenticateParams| {
|
|
||||||
let mut auth_ctx = auth_ctx.write().unwrap();
|
|
||||||
match (*auth_ctx).authenticate(params.invitation) {
|
|
||||||
Ok(Ok(session_token)) => warp::reply::json(&AuthenticateResponse { session_token }),
|
|
||||||
Ok(Err(auth_error)) => warp::reply::json(&ErrorResponse {
|
|
||||||
error: format!("{:?}", auth_error),
|
|
||||||
}),
|
|
||||||
Err(err) => panic!("{}", err),
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
fn list_users(
|
fn list_users(
|
||||||
auth_ctx: Arc<RwLock<impl AuthenticationDB>>,
|
auth_ctx: Arc<RwLock<impl AuthenticationDB>>,
|
||||||
) -> impl Filter<Extract = impl warp::Reply, Error = warp::Rejection> + Clone {
|
) -> impl Filter<Extract = impl warp::Reply, Error = warp::Rejection> + Clone {
|
||||||
|
@ -155,7 +99,6 @@ fn list_users(
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
pub async fn main() {
|
pub async fn main() {
|
||||||
|
@ -174,7 +117,7 @@ pub async fn main() {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
let echo_authenticated = warp::path!("api" / "v1" / "echo" / String)
|
let echo_authenticated = warp::path!("api" / "v1" / "echo" / String)
|
||||||
.and(with_session(auth_ctx.clone()))
|
.and(with_authentication(auth_ctx.clone()))
|
||||||
.map(|param: String, (username, userid)| {
|
.map(|param: String, (username, userid)| {
|
||||||
println!("param: {:?}", username);
|
println!("param: {:?}", username);
|
||||||
println!("param: {:?}", userid);
|
println!("param: {:?}", userid);
|
||||||
|
@ -182,17 +125,8 @@ pub async fn main() {
|
||||||
warp::reply::json(&vec!["authed", param.as_str()])
|
warp::reply::json(&vec!["authed", param.as_str()])
|
||||||
});
|
});
|
||||||
|
|
||||||
/*
|
|
||||||
let filter = list_users(auth_ctx.clone())
|
let filter = list_users(auth_ctx.clone())
|
||||||
.or(make_user(auth_ctx.clone()))
|
.or(make_user(auth_ctx.clone()))
|
||||||
.or(make_invitation(auth_ctx.clone()))
|
|
||||||
.or(authenticate(auth_ctx.clone()))
|
|
||||||
.or(echo_authenticated)
|
|
||||||
.or(echo_unauthenticated);
|
|
||||||
*/
|
|
||||||
let filter = make_user(auth_ctx.clone())
|
|
||||||
.or(make_invitation(auth_ctx.clone()))
|
|
||||||
.or(authenticate(auth_ctx.clone()))
|
|
||||||
.or(echo_authenticated)
|
.or(echo_authenticated)
|
||||||
.or(echo_unauthenticated);
|
.or(echo_unauthenticated);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue