mirror of
https://github.com/meilisearch/MeiliSearch
synced 2024-11-22 12:54:26 +01:00
prepare architecture for tests
This commit is contained in:
parent
38d41252e6
commit
5e2861ff55
@ -9,8 +9,8 @@ use meilisearch_core::{Database, Error as MError, MResult, MainT, UpdateT};
|
|||||||
use sha2::Digest;
|
use sha2::Digest;
|
||||||
use sysinfo::Pid;
|
use sysinfo::Pid;
|
||||||
|
|
||||||
|
use crate::index_update_callback;
|
||||||
use crate::option::Opt;
|
use crate::option::Opt;
|
||||||
use crate::routes::index_update_callback;
|
|
||||||
|
|
||||||
const LAST_UPDATE_KEY: &str = "last-update";
|
const LAST_UPDATE_KEY: &str = "last-update";
|
||||||
|
|
||||||
|
100
meilisearch-http/src/helpers/authentication.rs
Normal file
100
meilisearch-http/src/helpers/authentication.rs
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
use std::cell::RefCell;
|
||||||
|
use std::pin::Pin;
|
||||||
|
use std::rc::Rc;
|
||||||
|
use std::task::{Context, Poll};
|
||||||
|
|
||||||
|
use actix_service::{Service, Transform};
|
||||||
|
use actix_web::{dev::ServiceRequest, dev::ServiceResponse, Error};
|
||||||
|
use futures::future::{err, ok, Future, Ready};
|
||||||
|
|
||||||
|
use crate::error::ResponseError;
|
||||||
|
use crate::Data;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub enum Authentication {
|
||||||
|
Public,
|
||||||
|
Private,
|
||||||
|
Admin,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S: 'static, B> Transform<S> for Authentication
|
||||||
|
where
|
||||||
|
S: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
|
||||||
|
S::Future: 'static,
|
||||||
|
B: 'static,
|
||||||
|
{
|
||||||
|
type Request = ServiceRequest;
|
||||||
|
type Response = ServiceResponse<B>;
|
||||||
|
type Error = Error;
|
||||||
|
type InitError = ();
|
||||||
|
type Transform = LoggingMiddleware<S>;
|
||||||
|
type Future = Ready<Result<Self::Transform, Self::InitError>>;
|
||||||
|
|
||||||
|
fn new_transform(&self, service: S) -> Self::Future {
|
||||||
|
ok(LoggingMiddleware {
|
||||||
|
acl: (*self).clone(),
|
||||||
|
service: Rc::new(RefCell::new(service)),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct LoggingMiddleware<S> {
|
||||||
|
acl: Authentication,
|
||||||
|
service: Rc<RefCell<S>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S, B> Service for LoggingMiddleware<S>
|
||||||
|
where
|
||||||
|
S: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = Error> + 'static,
|
||||||
|
S::Future: 'static,
|
||||||
|
B: 'static,
|
||||||
|
{
|
||||||
|
type Request = ServiceRequest;
|
||||||
|
type Response = ServiceResponse<B>;
|
||||||
|
type Error = Error;
|
||||||
|
type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>>>>;
|
||||||
|
|
||||||
|
fn poll_ready(&mut self, cx: &mut Context) -> Poll<Result<(), Self::Error>> {
|
||||||
|
self.service.poll_ready(cx)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn call(&mut self, req: ServiceRequest) -> Self::Future {
|
||||||
|
let mut svc = self.service.clone();
|
||||||
|
let data = req.app_data::<Data>().unwrap();
|
||||||
|
|
||||||
|
if data.api_keys.master.is_none() {
|
||||||
|
return Box::pin(svc.call(req));
|
||||||
|
}
|
||||||
|
|
||||||
|
let auth_header = match req.headers().get("X-Meili-API-Key") {
|
||||||
|
Some(auth) => match auth.to_str() {
|
||||||
|
Ok(auth) => auth,
|
||||||
|
Err(_) => return Box::pin(err(ResponseError::MissingAuthorizationHeader.into())),
|
||||||
|
},
|
||||||
|
None => {
|
||||||
|
return Box::pin(err(ResponseError::MissingAuthorizationHeader.into()));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let authenticated = match self.acl {
|
||||||
|
Authentication::Admin => data.api_keys.master.as_deref() == Some(auth_header),
|
||||||
|
Authentication::Private => {
|
||||||
|
data.api_keys.master.as_deref() == Some(auth_header)
|
||||||
|
|| data.api_keys.private.as_deref() == Some(auth_header)
|
||||||
|
}
|
||||||
|
Authentication::Public => {
|
||||||
|
data.api_keys.master.as_deref() == Some(auth_header)
|
||||||
|
|| data.api_keys.private.as_deref() == Some(auth_header)
|
||||||
|
|| data.api_keys.public.as_deref() == Some(auth_header)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if authenticated {
|
||||||
|
Box::pin(svc.call(req))
|
||||||
|
} else {
|
||||||
|
Box::pin(err(
|
||||||
|
ResponseError::InvalidToken(auth_header.to_string()).into()
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,2 +1,4 @@
|
|||||||
|
pub mod authentication;
|
||||||
pub mod meilisearch;
|
pub mod meilisearch;
|
||||||
// pub mod tide;
|
|
||||||
|
pub use authentication::Authentication;
|
||||||
|
@ -1,83 +0,0 @@
|
|||||||
use crate::error::{ResponseError, SResult};
|
|
||||||
use crate::Data;
|
|
||||||
use meilisearch_core::Index;
|
|
||||||
use tide::Request;
|
|
||||||
|
|
||||||
pub enum ACL {
|
|
||||||
Admin,
|
|
||||||
Private,
|
|
||||||
Public,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait RequestExt {
|
|
||||||
fn is_allowed(&self, acl: ACL) -> SResult<()>;
|
|
||||||
fn url_param(&self, name: &str) -> SResult<String>;
|
|
||||||
fn index(&self) -> SResult<Index>;
|
|
||||||
fn document_id(&self) -> SResult<String>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RequestExt for Request<Data> {
|
|
||||||
fn is_allowed(&self, acl: ACL) -> SResult<()> {
|
|
||||||
let user_api_key = self.header("X-Meili-API-Key");
|
|
||||||
|
|
||||||
if self.state().api_keys.master.is_none() {
|
|
||||||
return Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
match acl {
|
|
||||||
ACL::Admin => {
|
|
||||||
if user_api_key == self.state().api_keys.master.as_deref() {
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ACL::Private => {
|
|
||||||
if user_api_key == self.state().api_keys.master.as_deref() {
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
if user_api_key == self.state().api_keys.private.as_deref() {
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ACL::Public => {
|
|
||||||
if user_api_key == self.state().api_keys.master.as_deref() {
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
if user_api_key == self.state().api_keys.private.as_deref() {
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
if user_api_key == self.state().api_keys.public.as_deref() {
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Err(ResponseError::InvalidToken(
|
|
||||||
user_api_key.unwrap_or("Need a token").to_owned(),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn url_param(&self, name: &str) -> SResult<String> {
|
|
||||||
let param = self
|
|
||||||
.param::<String>(name)
|
|
||||||
.map_err(|e| ResponseError::bad_parameter(name, e))?;
|
|
||||||
Ok(param)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn index(&self) -> SResult<Index> {
|
|
||||||
let index_uid = self.url_param("index")?;
|
|
||||||
let index = self
|
|
||||||
.state()
|
|
||||||
.db
|
|
||||||
.open_index(&index_uid)
|
|
||||||
.ok_or(ResponseError::index_not_found(index_uid))?;
|
|
||||||
Ok(index)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn document_id(&self) -> SResult<String> {
|
|
||||||
let name = self
|
|
||||||
.param::<String>("document_id")
|
|
||||||
.map_err(|_| ResponseError::bad_parameter("documentId", "primaryKey"))?;
|
|
||||||
|
|
||||||
Ok(name)
|
|
||||||
}
|
|
||||||
}
|
|
@ -8,3 +8,109 @@ pub mod option;
|
|||||||
pub mod routes;
|
pub mod routes;
|
||||||
|
|
||||||
pub use self::data::Data;
|
pub use self::data::Data;
|
||||||
|
use actix_http::Error;
|
||||||
|
use actix_service::ServiceFactory;
|
||||||
|
use actix_web::{dev, web, App};
|
||||||
|
use log::error;
|
||||||
|
use meilisearch_core::ProcessedUpdateResult;
|
||||||
|
|
||||||
|
pub fn create_app(
|
||||||
|
data: &Data,
|
||||||
|
) -> App<
|
||||||
|
impl ServiceFactory<
|
||||||
|
Config = (),
|
||||||
|
Request = dev::ServiceRequest,
|
||||||
|
Response = dev::ServiceResponse<actix_http::body::Body>,
|
||||||
|
Error = Error,
|
||||||
|
InitError = (),
|
||||||
|
>,
|
||||||
|
actix_http::body::Body,
|
||||||
|
> {
|
||||||
|
App::new()
|
||||||
|
.app_data(web::Data::new(data.clone()))
|
||||||
|
.wrap(helpers::Authentication::Public)
|
||||||
|
.service(routes::load_html)
|
||||||
|
.service(routes::load_css)
|
||||||
|
.service(routes::search::search_with_url_query)
|
||||||
|
.service(routes::search::search_multi_index)
|
||||||
|
.service(routes::document::get_document)
|
||||||
|
.service(routes::document::get_all_documents)
|
||||||
|
.wrap(helpers::Authentication::Private)
|
||||||
|
.service(routes::index::list_indexes)
|
||||||
|
.service(routes::index::get_index)
|
||||||
|
.service(routes::index::create_index)
|
||||||
|
.service(routes::index::update_index)
|
||||||
|
.service(routes::index::delete_index)
|
||||||
|
.service(routes::index::get_update_status)
|
||||||
|
.service(routes::index::get_all_updates_status)
|
||||||
|
.service(routes::document::delete_document)
|
||||||
|
.service(routes::document::add_documents)
|
||||||
|
.service(routes::document::update_documents)
|
||||||
|
.service(routes::document::delete_documents)
|
||||||
|
.service(routes::document::clear_all_documents)
|
||||||
|
.service(routes::setting::update_all)
|
||||||
|
.service(routes::setting::get_all)
|
||||||
|
.service(routes::setting::delete_all)
|
||||||
|
.service(routes::setting::get_rules)
|
||||||
|
.service(routes::setting::update_rules)
|
||||||
|
.service(routes::setting::delete_rules)
|
||||||
|
.service(routes::setting::get_distinct)
|
||||||
|
.service(routes::setting::update_distinct)
|
||||||
|
.service(routes::setting::delete_distinct)
|
||||||
|
.service(routes::setting::get_searchable)
|
||||||
|
.service(routes::setting::update_searchable)
|
||||||
|
.service(routes::setting::delete_searchable)
|
||||||
|
.service(routes::setting::get_displayed)
|
||||||
|
.service(routes::setting::update_displayed)
|
||||||
|
.service(routes::setting::delete_displayed)
|
||||||
|
.service(routes::setting::get_accept_new_fields)
|
||||||
|
.service(routes::setting::update_accept_new_fields)
|
||||||
|
.service(routes::stop_words::get)
|
||||||
|
.service(routes::stop_words::update)
|
||||||
|
.service(routes::stop_words::delete)
|
||||||
|
.service(routes::synonym::get)
|
||||||
|
.service(routes::synonym::update)
|
||||||
|
.service(routes::synonym::delete)
|
||||||
|
.service(routes::stats::index_stats)
|
||||||
|
.service(routes::stats::get_stats)
|
||||||
|
.service(routes::stats::get_version)
|
||||||
|
.service(routes::stats::get_sys_info)
|
||||||
|
.service(routes::stats::get_sys_info_pretty)
|
||||||
|
.service(routes::health::get_health)
|
||||||
|
.service(routes::health::change_healthyness)
|
||||||
|
.wrap(helpers::Authentication::Admin)
|
||||||
|
.service(routes::key::list)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn index_update_callback(index_uid: &str, data: &Data, status: ProcessedUpdateResult) {
|
||||||
|
if status.error.is_some() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(index) = data.db.open_index(&index_uid) {
|
||||||
|
let db = &data.db;
|
||||||
|
let mut writer = match db.main_write_txn() {
|
||||||
|
Ok(writer) => writer,
|
||||||
|
Err(e) => {
|
||||||
|
error!("Impossible to get write_txn; {}", e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Err(e) = data.compute_stats(&mut writer, &index_uid) {
|
||||||
|
error!("Impossible to compute stats; {}", e)
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Err(e) = data.set_last_update(&mut writer) {
|
||||||
|
error!("Impossible to update last_update; {}", e)
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Err(e) = index.main.put_updated_at(&mut writer) {
|
||||||
|
error!("Impossible to update updated_at; {}", e)
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Err(e) = writer.commit() {
|
||||||
|
error!("Impossible to get write_txn; {}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,13 +1,12 @@
|
|||||||
use std::{env, thread};
|
use std::{env, thread};
|
||||||
|
|
||||||
use actix_cors::Cors;
|
use actix_cors::Cors;
|
||||||
use actix_web::{middleware, web, App, HttpServer};
|
use actix_web::{middleware, HttpServer};
|
||||||
use log::info;
|
use log::info;
|
||||||
use main_error::MainError;
|
use main_error::MainError;
|
||||||
use meilisearch_http::data::Data;
|
use meilisearch_http::data::Data;
|
||||||
use meilisearch_http::option::Opt;
|
use meilisearch_http::option::Opt;
|
||||||
use meilisearch_http::routes;
|
use meilisearch_http::{create_app, index_update_callback};
|
||||||
use meilisearch_http::routes::index_update_callback;
|
|
||||||
use structopt::StructOpt;
|
use structopt::StructOpt;
|
||||||
|
|
||||||
mod analytics;
|
mod analytics;
|
||||||
@ -51,7 +50,7 @@ async fn main() -> Result<(), MainError> {
|
|||||||
print_launch_resume(&opt, &data);
|
print_launch_resume(&opt, &data);
|
||||||
|
|
||||||
HttpServer::new(move || {
|
HttpServer::new(move || {
|
||||||
App::new()
|
create_app(&data)
|
||||||
.wrap(
|
.wrap(
|
||||||
Cors::new()
|
Cors::new()
|
||||||
.send_wildcard()
|
.send_wildcard()
|
||||||
@ -60,59 +59,6 @@ async fn main() -> Result<(), MainError> {
|
|||||||
)
|
)
|
||||||
.wrap(middleware::Logger::default())
|
.wrap(middleware::Logger::default())
|
||||||
.wrap(middleware::Compress::default())
|
.wrap(middleware::Compress::default())
|
||||||
.app_data(web::Data::new(data.clone()))
|
|
||||||
.wrap(routes::Authentication::Public)
|
|
||||||
.service(routes::load_html)
|
|
||||||
.service(routes::load_css)
|
|
||||||
.service(routes::search::search_with_url_query)
|
|
||||||
.service(routes::search::search_multi_index)
|
|
||||||
.service(routes::document::get_document)
|
|
||||||
.service(routes::document::get_all_documents)
|
|
||||||
.wrap(routes::Authentication::Private)
|
|
||||||
.service(routes::index::list_indexes)
|
|
||||||
.service(routes::index::get_index)
|
|
||||||
.service(routes::index::create_index)
|
|
||||||
.service(routes::index::update_index)
|
|
||||||
.service(routes::index::delete_index)
|
|
||||||
.service(routes::index::get_update_status)
|
|
||||||
.service(routes::index::get_all_updates_status)
|
|
||||||
.service(routes::document::delete_document)
|
|
||||||
.service(routes::document::add_documents)
|
|
||||||
.service(routes::document::update_documents)
|
|
||||||
.service(routes::document::delete_documents)
|
|
||||||
.service(routes::document::clear_all_documents)
|
|
||||||
.service(routes::setting::update_all)
|
|
||||||
.service(routes::setting::get_all)
|
|
||||||
.service(routes::setting::delete_all)
|
|
||||||
.service(routes::setting::get_rules)
|
|
||||||
.service(routes::setting::update_rules)
|
|
||||||
.service(routes::setting::delete_rules)
|
|
||||||
.service(routes::setting::get_distinct)
|
|
||||||
.service(routes::setting::update_distinct)
|
|
||||||
.service(routes::setting::delete_distinct)
|
|
||||||
.service(routes::setting::get_searchable)
|
|
||||||
.service(routes::setting::update_searchable)
|
|
||||||
.service(routes::setting::delete_searchable)
|
|
||||||
.service(routes::setting::get_displayed)
|
|
||||||
.service(routes::setting::update_displayed)
|
|
||||||
.service(routes::setting::delete_displayed)
|
|
||||||
.service(routes::setting::get_accept_new_fields)
|
|
||||||
.service(routes::setting::update_accept_new_fields)
|
|
||||||
.service(routes::stop_words::get)
|
|
||||||
.service(routes::stop_words::update)
|
|
||||||
.service(routes::stop_words::delete)
|
|
||||||
.service(routes::synonym::get)
|
|
||||||
.service(routes::synonym::update)
|
|
||||||
.service(routes::synonym::delete)
|
|
||||||
.service(routes::stats::index_stats)
|
|
||||||
.service(routes::stats::get_stats)
|
|
||||||
.service(routes::stats::get_version)
|
|
||||||
.service(routes::stats::get_sys_info)
|
|
||||||
.service(routes::stats::get_sys_info_pretty)
|
|
||||||
.service(routes::health::get_health)
|
|
||||||
.service(routes::health::change_healthyness)
|
|
||||||
.wrap(routes::Authentication::Admin)
|
|
||||||
.service(routes::key::list)
|
|
||||||
})
|
})
|
||||||
.bind(opt.http_addr)?
|
.bind(opt.http_addr)?
|
||||||
.run()
|
.run()
|
||||||
|
@ -1,19 +1,6 @@
|
|||||||
use std::cell::RefCell;
|
|
||||||
use std::pin::Pin;
|
|
||||||
use std::rc::Rc;
|
|
||||||
use std::task::{Context, Poll};
|
|
||||||
|
|
||||||
use actix_service::{Service, Transform};
|
|
||||||
use actix_web::{dev::ServiceRequest, dev::ServiceResponse, Error};
|
|
||||||
use actix_web::{get, HttpResponse};
|
use actix_web::{get, HttpResponse};
|
||||||
use futures::future::{err, ok, Future, Ready};
|
|
||||||
use log::error;
|
|
||||||
use meilisearch_core::ProcessedUpdateResult;
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::error::ResponseError;
|
|
||||||
use crate::Data;
|
|
||||||
|
|
||||||
pub mod document;
|
pub mod document;
|
||||||
pub mod health;
|
pub mod health;
|
||||||
pub mod index;
|
pub mod index;
|
||||||
@ -54,125 +41,3 @@ pub async fn load_css() -> HttpResponse {
|
|||||||
.content_type("text/css; charset=utf-8")
|
.content_type("text/css; charset=utf-8")
|
||||||
.body(include_str!("../../public/bulma.min.css").to_string())
|
.body(include_str!("../../public/bulma.min.css").to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn index_update_callback(index_uid: &str, data: &Data, status: ProcessedUpdateResult) {
|
|
||||||
if status.error.is_some() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(index) = data.db.open_index(&index_uid) {
|
|
||||||
let db = &data.db;
|
|
||||||
let mut writer = match db.main_write_txn() {
|
|
||||||
Ok(writer) => writer,
|
|
||||||
Err(e) => {
|
|
||||||
error!("Impossible to get write_txn; {}", e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Err(e) = data.compute_stats(&mut writer, &index_uid) {
|
|
||||||
error!("Impossible to compute stats; {}", e)
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Err(e) = data.set_last_update(&mut writer) {
|
|
||||||
error!("Impossible to update last_update; {}", e)
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Err(e) = index.main.put_updated_at(&mut writer) {
|
|
||||||
error!("Impossible to update updated_at; {}", e)
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Err(e) = writer.commit() {
|
|
||||||
error!("Impossible to get write_txn; {}", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub enum Authentication {
|
|
||||||
Public,
|
|
||||||
Private,
|
|
||||||
Admin,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S: 'static, B> Transform<S> for Authentication
|
|
||||||
where
|
|
||||||
S: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
|
|
||||||
S::Future: 'static,
|
|
||||||
B: 'static,
|
|
||||||
{
|
|
||||||
type Request = ServiceRequest;
|
|
||||||
type Response = ServiceResponse<B>;
|
|
||||||
type Error = Error;
|
|
||||||
type InitError = ();
|
|
||||||
type Transform = LoggingMiddleware<S>;
|
|
||||||
type Future = Ready<Result<Self::Transform, Self::InitError>>;
|
|
||||||
|
|
||||||
fn new_transform(&self, service: S) -> Self::Future {
|
|
||||||
ok(LoggingMiddleware {
|
|
||||||
acl: (*self).clone(),
|
|
||||||
service: Rc::new(RefCell::new(service)),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct LoggingMiddleware<S> {
|
|
||||||
acl: Authentication,
|
|
||||||
service: Rc<RefCell<S>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S, B> Service for LoggingMiddleware<S>
|
|
||||||
where
|
|
||||||
S: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = Error> + 'static,
|
|
||||||
S::Future: 'static,
|
|
||||||
B: 'static,
|
|
||||||
{
|
|
||||||
type Request = ServiceRequest;
|
|
||||||
type Response = ServiceResponse<B>;
|
|
||||||
type Error = Error;
|
|
||||||
type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>>>>;
|
|
||||||
|
|
||||||
fn poll_ready(&mut self, cx: &mut Context) -> Poll<Result<(), Self::Error>> {
|
|
||||||
self.service.poll_ready(cx)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn call(&mut self, req: ServiceRequest) -> Self::Future {
|
|
||||||
let mut svc = self.service.clone();
|
|
||||||
let data = req.app_data::<Data>().unwrap();
|
|
||||||
|
|
||||||
if data.api_keys.master.is_none() {
|
|
||||||
return Box::pin(svc.call(req));
|
|
||||||
}
|
|
||||||
|
|
||||||
let auth_header = match req.headers().get("X-Meili-API-Key") {
|
|
||||||
Some(auth) => match auth.to_str() {
|
|
||||||
Ok(auth) => auth,
|
|
||||||
Err(_) => return Box::pin(err(ResponseError::MissingAuthorizationHeader.into())),
|
|
||||||
},
|
|
||||||
None => {
|
|
||||||
return Box::pin(err(ResponseError::MissingAuthorizationHeader.into()));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let authenticated = match self.acl {
|
|
||||||
Authentication::Admin => data.api_keys.master.as_deref() == Some(auth_header),
|
|
||||||
Authentication::Private => {
|
|
||||||
data.api_keys.master.as_deref() == Some(auth_header)
|
|
||||||
|| data.api_keys.private.as_deref() == Some(auth_header)
|
|
||||||
}
|
|
||||||
Authentication::Public => {
|
|
||||||
data.api_keys.master.as_deref() == Some(auth_header)
|
|
||||||
|| data.api_keys.private.as_deref() == Some(auth_header)
|
|
||||||
|| data.api_keys.public.as_deref() == Some(auth_header)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if authenticated {
|
|
||||||
Box::pin(svc.call(req))
|
|
||||||
} else {
|
|
||||||
Box::pin(err(
|
|
||||||
ResponseError::InvalidToken(auth_header.to_string()).into()
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user