mirror of https://github.com/veypi/OneAuth.git
update
parent
c180cd4241
commit
dfd1549f11
@ -0,0 +1,126 @@
|
|||||||
|
//
|
||||||
|
// app.rs
|
||||||
|
// Copyright (C) 2023 veypi <i@veypi.com>
|
||||||
|
// 2023-11-07 00:58
|
||||||
|
// Distributed under terms of the MIT license.
|
||||||
|
//
|
||||||
|
|
||||||
|
use std::{fs, path::Path};
|
||||||
|
|
||||||
|
use actix_web::web;
|
||||||
|
|
||||||
|
use dav_server::{
|
||||||
|
actix::{DavRequest, DavResponse},
|
||||||
|
body::Body,
|
||||||
|
fakels::FakeLs,
|
||||||
|
localfs::LocalFs,
|
||||||
|
DavConfig, DavHandler,
|
||||||
|
};
|
||||||
|
|
||||||
|
use http::Response;
|
||||||
|
use http_auth_basic::Credentials;
|
||||||
|
use sea_orm::{ColumnTrait, EntityTrait, QueryFilter};
|
||||||
|
use tracing::{info, warn};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
models::{self, UserPlugin},
|
||||||
|
AppState, Error, Result,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn client() -> DavHandler {
|
||||||
|
DavHandler::builder()
|
||||||
|
.locksystem(FakeLs::new())
|
||||||
|
.strip_prefix("/fs/a/")
|
||||||
|
.build_handler()
|
||||||
|
}
|
||||||
|
pub async fn dav_handler(
|
||||||
|
id: web::Path<(String, String)>,
|
||||||
|
req: DavRequest,
|
||||||
|
davhandler: web::Data<DavHandler>,
|
||||||
|
stat: web::Data<AppState>,
|
||||||
|
) -> DavResponse {
|
||||||
|
let root = stat.fs_root.clone();
|
||||||
|
let id = id.into_inner().0;
|
||||||
|
info!("start app: {}", id);
|
||||||
|
match handle_file(&req, stat).await {
|
||||||
|
Ok(()) => {
|
||||||
|
let p = Path::new(&root).join(format!("app/{}/", id));
|
||||||
|
if !p.exists() {
|
||||||
|
match fs::create_dir_all(p.clone()) {
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(e) => {
|
||||||
|
warn!("{}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
info!("mount {}", p.to_str().unwrap());
|
||||||
|
let config = DavConfig::new()
|
||||||
|
.filesystem(LocalFs::new(p, false, false, true))
|
||||||
|
.strip_prefix(format!("/fs/a/{}/", id));
|
||||||
|
davhandler.handle_with(config, req.request).await.into()
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
warn!("handle file failed: {}", e);
|
||||||
|
Response::builder()
|
||||||
|
.status(401)
|
||||||
|
.header("WWW-Authenticate", "Basic realm=\"file\"")
|
||||||
|
.body(Body::from("please auth".to_string()))
|
||||||
|
.unwrap()
|
||||||
|
.into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn handle_file(
|
||||||
|
req: &dav_server::actix::DavRequest,
|
||||||
|
stat: web::Data<AppState>,
|
||||||
|
) -> Result<()> {
|
||||||
|
let p = req.request.uri();
|
||||||
|
let headers = req.request.headers();
|
||||||
|
let m = req.request.method();
|
||||||
|
info!("access {} to {}", m, p);
|
||||||
|
let authorization = headers.get("authorization");
|
||||||
|
match authorization {
|
||||||
|
Some(au) => {
|
||||||
|
if let Some((auth_type, encoded_credentials)) =
|
||||||
|
au.to_str().unwrap_or("").split_once(' ')
|
||||||
|
{
|
||||||
|
if encoded_credentials.contains(' ') {
|
||||||
|
// Invalid authorization token received
|
||||||
|
return Err(Error::InvalidToken);
|
||||||
|
}
|
||||||
|
match auth_type.to_lowercase().as_str() {
|
||||||
|
"basic" => {
|
||||||
|
let credentials = Credentials::decode(encoded_credentials.to_string())?;
|
||||||
|
info!("{}|{}", credentials.user_id, credentials.password);
|
||||||
|
if credentials.user_id == "cli" && credentials.password == "cli" {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
match models::user::Entity::find()
|
||||||
|
.filter(models::user::Column::Username.eq(credentials.user_id))
|
||||||
|
.one(stat.db())
|
||||||
|
.await?
|
||||||
|
{
|
||||||
|
Some(u) => {
|
||||||
|
u.check_pass(&credentials.password)?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"bearer" => {
|
||||||
|
let t = models::Token::from(encoded_credentials, &stat.key)?;
|
||||||
|
if t.is_valid() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return Err(Error::InvalidScheme(auth_type.to_string()));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
|
Err(Error::NotAuthed)
|
||||||
|
}
|
@ -0,0 +1,131 @@
|
|||||||
|
//
|
||||||
|
// mod.rs
|
||||||
|
// Copyright (C) 2023 veypi <i@veypi.com>
|
||||||
|
// 2023-11-07 00:07
|
||||||
|
// Distributed under terms of the MIT license.
|
||||||
|
//
|
||||||
|
|
||||||
|
mod app;
|
||||||
|
mod usr;
|
||||||
|
use std::future::{ready, Ready};
|
||||||
|
|
||||||
|
use actix_web::{
|
||||||
|
dev::{forward_ready, Service, ServiceRequest, ServiceResponse, Transform},
|
||||||
|
web, Error,
|
||||||
|
};
|
||||||
|
use futures_util::future::LocalBoxFuture;
|
||||||
|
|
||||||
|
pub fn routes(cfg: &mut web::ServiceConfig) {
|
||||||
|
cfg.service(
|
||||||
|
actix_web::web::scope("u")
|
||||||
|
.app_data(web::Data::new(usr::client()))
|
||||||
|
.service(web::resource("/{tail:.*}").to(usr::dav_handler)),
|
||||||
|
);
|
||||||
|
cfg.service(
|
||||||
|
actix_web::web::scope("a")
|
||||||
|
.app_data(web::Data::new(app::client()))
|
||||||
|
.service(web::resource("/{id}/{tail:.*}").to(app::dav_handler)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct FsWrap;
|
||||||
|
|
||||||
|
impl<S, B> Transform<S, ServiceRequest> for FsWrap
|
||||||
|
where
|
||||||
|
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
|
||||||
|
S::Future: 'static,
|
||||||
|
B: 'static,
|
||||||
|
{
|
||||||
|
type Response = ServiceResponse<B>;
|
||||||
|
type Error = Error;
|
||||||
|
type InitError = ();
|
||||||
|
type Transform = FsMiddleware<S>;
|
||||||
|
type Future = Ready<Result<Self::Transform, Self::InitError>>;
|
||||||
|
|
||||||
|
fn new_transform(&self, service: S) -> Self::Future {
|
||||||
|
ready(Ok(FsMiddleware { service }))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct FsMiddleware<S> {
|
||||||
|
service: S,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S, B> Service<ServiceRequest> for FsMiddleware<S>
|
||||||
|
where
|
||||||
|
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
|
||||||
|
S::Future: 'static,
|
||||||
|
B: 'static,
|
||||||
|
{
|
||||||
|
type Response = ServiceResponse<B>;
|
||||||
|
type Error = Error;
|
||||||
|
type Future = LocalBoxFuture<'static, Result<Self::Response, Self::Error>>;
|
||||||
|
|
||||||
|
forward_ready!(service);
|
||||||
|
|
||||||
|
fn call(&self, req: ServiceRequest) -> Self::Future {
|
||||||
|
println!("start fs: {}", req.path());
|
||||||
|
let reqheaders = req.headers().clone();
|
||||||
|
let is_preflight = is_request_preflight(&req);
|
||||||
|
let fut = self.service.call(req);
|
||||||
|
|
||||||
|
Box::pin(async move {
|
||||||
|
let mut res = fut.await?;
|
||||||
|
if is_preflight {
|
||||||
|
let mut rt = actix_web::HttpResponse::Ok();
|
||||||
|
if let Some(o) = reqheaders.get("Access-Control-Request-Headers") {
|
||||||
|
rt.insert_header(("Access-Control-Allow-Headers", o.to_str().unwrap_or("")));
|
||||||
|
};
|
||||||
|
if let Some(o) = reqheaders.get("Access-Control-Request-Method") {
|
||||||
|
rt.insert_header(("Access-Control-Allow-Methods", o.to_str().unwrap_or("")));
|
||||||
|
};
|
||||||
|
if let Some(o) = reqheaders.get("Origin") {
|
||||||
|
rt.insert_header(("Access-Control-Allow-Origin", o.to_str().unwrap_or("")));
|
||||||
|
};
|
||||||
|
rt.insert_header((
|
||||||
|
"Access-Control-Expose-Headers",
|
||||||
|
"access-control-allow-origin, content-type",
|
||||||
|
));
|
||||||
|
rt.insert_header(("Access-Control-Allow-Credentials", "true"));
|
||||||
|
rt.insert_header(("WWW-Authenticate", "Basic realm=\"file\""));
|
||||||
|
res = ServiceResponse::new(
|
||||||
|
res.request().to_owned(),
|
||||||
|
rt.message_body(res.into_body())?,
|
||||||
|
);
|
||||||
|
return Ok(res);
|
||||||
|
} else if let Some(o) = reqheaders.get("Origin") {
|
||||||
|
res.headers_mut().insert(
|
||||||
|
http::header::HeaderName::try_from("Access-Control-Allow-Origin").unwrap(),
|
||||||
|
o.to_owned(),
|
||||||
|
);
|
||||||
|
};
|
||||||
|
Ok(res)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Try to parse header value as HTTP method.
|
||||||
|
fn header_value_try_into_method(hdr: &http::header::HeaderValue) -> Option<http::Method> {
|
||||||
|
hdr.to_str()
|
||||||
|
.ok()
|
||||||
|
.and_then(|meth| http::Method::try_from(meth).ok())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_request_preflight(req: &ServiceRequest) -> bool {
|
||||||
|
// check request method is OPTIONS
|
||||||
|
if req.method() != http::Method::OPTIONS {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check follow-up request method is present and valid
|
||||||
|
if req
|
||||||
|
.headers()
|
||||||
|
.get(http::header::ACCESS_CONTROL_REQUEST_METHOD)
|
||||||
|
.and_then(header_value_try_into_method)
|
||||||
|
.is_none()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
@ -0,0 +1,116 @@
|
|||||||
|
//
|
||||||
|
// fs.rs
|
||||||
|
// Copyright (C) 2023 veypi <i@veypi.com>
|
||||||
|
// 2023-10-02 22:51
|
||||||
|
// Distributed under terms of the MIT license.
|
||||||
|
//
|
||||||
|
//
|
||||||
|
|
||||||
|
use std::{fs, path::Path};
|
||||||
|
|
||||||
|
use actix_web::web;
|
||||||
|
|
||||||
|
use dav_server::{
|
||||||
|
actix::{DavRequest, DavResponse},
|
||||||
|
body::Body,
|
||||||
|
fakels::FakeLs,
|
||||||
|
localfs::LocalFs,
|
||||||
|
DavConfig, DavHandler,
|
||||||
|
};
|
||||||
|
|
||||||
|
use http::Response;
|
||||||
|
use http_auth_basic::Credentials;
|
||||||
|
use sea_orm::{ColumnTrait, EntityTrait, QueryFilter};
|
||||||
|
use tracing::{info, warn};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
models::{self, UserPlugin},
|
||||||
|
AppState, Error, Result,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn client() -> DavHandler {
|
||||||
|
DavHandler::builder()
|
||||||
|
.locksystem(FakeLs::new())
|
||||||
|
.strip_prefix("/fs/u/")
|
||||||
|
.build_handler()
|
||||||
|
}
|
||||||
|
pub async fn dav_handler(
|
||||||
|
req: DavRequest,
|
||||||
|
davhandler: web::Data<DavHandler>,
|
||||||
|
stat: web::Data<AppState>,
|
||||||
|
) -> DavResponse {
|
||||||
|
let root = stat.fs_root.clone();
|
||||||
|
match handle_file(&req, stat).await {
|
||||||
|
Ok(p) => {
|
||||||
|
let p = Path::new(&root).join(p);
|
||||||
|
if !p.exists() {
|
||||||
|
match fs::create_dir_all(p.clone()) {
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(e) => {
|
||||||
|
warn!("{}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
info!("mount {}", p.to_str().unwrap());
|
||||||
|
let config = DavConfig::new().filesystem(LocalFs::new(p, false, false, true));
|
||||||
|
davhandler.handle_with(config, req.request).await.into()
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
warn!("handle file failed: {}", e);
|
||||||
|
Response::builder()
|
||||||
|
.status(401)
|
||||||
|
.header("WWW-Authenticate", "Basic realm=\"file\"")
|
||||||
|
.body(Body::from("please auth".to_string()))
|
||||||
|
.unwrap()
|
||||||
|
.into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn handle_file(req: &DavRequest, stat: web::Data<AppState>) -> Result<String> {
|
||||||
|
let p = req.request.uri();
|
||||||
|
let headers = req.request.headers();
|
||||||
|
let m = req.request.method();
|
||||||
|
info!("access {} to {}", m, p);
|
||||||
|
let authorization = headers.get("authorization");
|
||||||
|
match authorization {
|
||||||
|
Some(au) => {
|
||||||
|
if let Some((auth_type, encoded_credentials)) =
|
||||||
|
au.to_str().unwrap_or("").split_once(' ')
|
||||||
|
{
|
||||||
|
if encoded_credentials.contains(' ') {
|
||||||
|
// Invalid authorization token received
|
||||||
|
return Err(Error::InvalidToken);
|
||||||
|
}
|
||||||
|
match auth_type.to_lowercase().as_str() {
|
||||||
|
"basic" => {
|
||||||
|
let credentials = Credentials::decode(encoded_credentials.to_string())?;
|
||||||
|
info!("{}|{}", credentials.user_id, credentials.password);
|
||||||
|
match models::user::Entity::find()
|
||||||
|
.filter(models::user::Column::Username.eq(credentials.user_id))
|
||||||
|
.one(stat.db())
|
||||||
|
.await?
|
||||||
|
{
|
||||||
|
Some(u) => {
|
||||||
|
u.check_pass(&credentials.password)?;
|
||||||
|
return Ok(format!("user/{}/", u.id));
|
||||||
|
}
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"bearer" => {
|
||||||
|
let t = models::Token::from(encoded_credentials, &stat.key)?;
|
||||||
|
if t.is_valid() {
|
||||||
|
return Ok(format!("user/{}/", t.id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return Err(Error::InvalidScheme(auth_type.to_string()));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
|
Err(Error::NotAuthed)
|
||||||
|
}
|
@ -1,178 +0,0 @@
|
|||||||
//
|
|
||||||
// fs.rs
|
|
||||||
// Copyright (C) 2023 veypi <i@veypi.com>
|
|
||||||
// 2023-10-02 22:51
|
|
||||||
// Distributed under terms of the MIT license.
|
|
||||||
//
|
|
||||||
//
|
|
||||||
|
|
||||||
use std::{fs, path::Path};
|
|
||||||
|
|
||||||
use actix_web::web;
|
|
||||||
|
|
||||||
use dav_server::{
|
|
||||||
actix::{DavRequest, DavResponse},
|
|
||||||
body::Body,
|
|
||||||
fakels::FakeLs,
|
|
||||||
localfs::LocalFs,
|
|
||||||
DavConfig, DavHandler,
|
|
||||||
};
|
|
||||||
|
|
||||||
use http::{header, Method, Response};
|
|
||||||
use http_auth_basic::Credentials;
|
|
||||||
use sea_orm::{ColumnTrait, EntityTrait, QueryFilter};
|
|
||||||
use tracing::{info, warn};
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
models::{self, UserPlugin},
|
|
||||||
AppState, Error, Result,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn core() -> DavHandler {
|
|
||||||
DavHandler::builder()
|
|
||||||
.locksystem(FakeLs::new())
|
|
||||||
.strip_prefix("/file/")
|
|
||||||
.build_handler()
|
|
||||||
}
|
|
||||||
/// Try to parse header value as HTTP method.
|
|
||||||
fn header_value_try_into_method(hdr: &header::HeaderValue) -> Option<Method> {
|
|
||||||
hdr.to_str()
|
|
||||||
.ok()
|
|
||||||
.and_then(|meth| Method::try_from(meth).ok())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_request_preflight(req: &DavRequest) -> bool {
|
|
||||||
// check request method is OPTIONS
|
|
||||||
if req.request.method() != Method::OPTIONS {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check follow-up request method is present and valid
|
|
||||||
if req
|
|
||||||
.request
|
|
||||||
.headers()
|
|
||||||
.get(header::ACCESS_CONTROL_REQUEST_METHOD)
|
|
||||||
.and_then(header_value_try_into_method)
|
|
||||||
.is_none()
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn dav_handler(
|
|
||||||
req: DavRequest,
|
|
||||||
davhandler: web::Data<DavHandler>,
|
|
||||||
stat: web::Data<AppState>,
|
|
||||||
) -> DavResponse {
|
|
||||||
let root = stat.fs_root.clone();
|
|
||||||
match handle_file(&req, stat).await {
|
|
||||||
Ok(p) => {
|
|
||||||
let p = Path::new(&root).join(p);
|
|
||||||
if !p.exists() {
|
|
||||||
match fs::create_dir_all(p.clone()) {
|
|
||||||
Ok(_) => {}
|
|
||||||
Err(e) => {
|
|
||||||
warn!("{}", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
info!("mount {}", p.to_str().unwrap());
|
|
||||||
let config = DavConfig::new().filesystem(LocalFs::new(p, false, false, true));
|
|
||||||
davhandler.handle_with(config, req.request).await.into()
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
warn!("handle file failed: {}", e);
|
|
||||||
if is_request_preflight(&req) {
|
|
||||||
let origin = match req.request.headers().get("Origin") {
|
|
||||||
Some(o) => o.to_str().unwrap(),
|
|
||||||
None => "",
|
|
||||||
};
|
|
||||||
let allowed_headers =
|
|
||||||
match req.request.headers().get("Access-Control-Request-Headers") {
|
|
||||||
Some(o) => o.to_str().unwrap(),
|
|
||||||
None => "",
|
|
||||||
};
|
|
||||||
let allowed_method =
|
|
||||||
match req.request.headers().get("Access-Control-Request-Method") {
|
|
||||||
Some(o) => o.to_str().unwrap(),
|
|
||||||
None => "",
|
|
||||||
};
|
|
||||||
Response::builder()
|
|
||||||
.status(200)
|
|
||||||
.header("WWW-Authenticate", "Basic realm=\"file\"")
|
|
||||||
.header("Access-Control-Allow-Origin", origin)
|
|
||||||
.header("Access-Control-Allow-Credentials", "true")
|
|
||||||
.header("Access-Control-Allow-Headers", allowed_headers)
|
|
||||||
.header("Access-Control-Allow-Methods", allowed_method)
|
|
||||||
.header(
|
|
||||||
"Access-Control-Expose-Headers",
|
|
||||||
"access-control-allow-origin, content-type",
|
|
||||||
)
|
|
||||||
.body(Body::from("please auth".to_string()))
|
|
||||||
.unwrap()
|
|
||||||
.into()
|
|
||||||
} else {
|
|
||||||
Response::builder()
|
|
||||||
.status(401)
|
|
||||||
.header("WWW-Authenticate", "Basic realm=\"file\"")
|
|
||||||
.body(Body::from("please auth".to_string()))
|
|
||||||
.unwrap()
|
|
||||||
.into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn handle_file(req: &DavRequest, stat: web::Data<AppState>) -> Result<String> {
|
|
||||||
let p = req.request.uri();
|
|
||||||
let headers = req.request.headers();
|
|
||||||
let m = req.request.method();
|
|
||||||
// handle_authorization(req.request.headers());
|
|
||||||
info!("access {} to {}", m, p);
|
|
||||||
let auth_token = headers.get("auth_token");
|
|
||||||
let authorization = headers.get("authorization");
|
|
||||||
let app_id = match headers.get("app_id") {
|
|
||||||
Some(i) => i.to_str().unwrap_or(""),
|
|
||||||
None => "",
|
|
||||||
};
|
|
||||||
match auth_token {
|
|
||||||
Some(t) => match models::Token::from(t.to_str().unwrap_or(""), &stat.key) {
|
|
||||||
Ok(t) => {
|
|
||||||
if t.is_valid() {
|
|
||||||
if app_id != "" {
|
|
||||||
// 只有秘钥才能访问app数据
|
|
||||||
if t.can_read("app", app_id) {
|
|
||||||
return Ok(format!("app/{}/", app_id));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return Ok(format!("user/{}/", t.id));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(_) => {}
|
|
||||||
},
|
|
||||||
None => {}
|
|
||||||
}
|
|
||||||
match authorization {
|
|
||||||
Some(au) => {
|
|
||||||
let credentials =
|
|
||||||
Credentials::from_header(au.to_str().unwrap_or("").to_string()).unwrap();
|
|
||||||
info!("{}|{}", credentials.user_id, credentials.password);
|
|
||||||
match models::user::Entity::find()
|
|
||||||
.filter(models::user::Column::Username.eq(credentials.user_id))
|
|
||||||
.one(stat.db())
|
|
||||||
.await?
|
|
||||||
{
|
|
||||||
Some(u) => {
|
|
||||||
u.check_pass(&credentials.password)?;
|
|
||||||
return Ok(format!("user/{}/", u.id));
|
|
||||||
}
|
|
||||||
None => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => {}
|
|
||||||
}
|
|
||||||
Err(Error::NotAuthed)
|
|
||||||
}
|
|
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue