introduce new key management

This commit is contained in:
qdequele 2020-02-06 15:41:11 +01:00
parent 5ac757a5fd
commit 257b7b4df4
No known key found for this signature in database
GPG key ID: B3F0A000EBF11745
18 changed files with 204 additions and 362 deletions

View file

@ -1,14 +1,16 @@
use crate::error::{ResponseError, SResult};
use crate::models::token::*;
use crate::Data;
use chrono::Utc;
use heed::types::{SerdeBincode, Str};
use meilisearch_core::Index;
use tide::Request;
pub enum ACL {
Admin,
Private,
Public
}
pub trait RequestExt {
fn is_allowed(&self, acl: ACL) -> SResult<()>;
fn header(&self, name: &str) -> SResult<String>;
fn url_param(&self, name: &str) -> SResult<String>;
fn index(&self) -> SResult<Index>;
fn identifier(&self) -> SResult<String>;
@ -16,73 +18,36 @@ pub trait RequestExt {
impl RequestExt for Request<Data> {
fn is_allowed(&self, acl: ACL) -> SResult<()> {
let api_key = match &self.state().api_key {
Some(api_key) => api_key,
None => return Ok(()),
};
let user_api_key = self.header("X-Meili-API-Key");
let user_api_key = self
.header("X-Meili-API-Key")
.ok_or(ResponseError::missing_header("X-Meili-API-Key"))?;
if user_api_key == *api_key {
return Ok(());
}
let request_index: Option<String> = None; //self.param::<String>("index").ok();
let db = &self.state().db;
let reader = db.main_read_txn()?;
let token_key = format!("{}{}", TOKEN_PREFIX_KEY, user_api_key);
let token_config = db
.common_store()
.get::<_, Str, SerdeBincode<Token>>(&reader, &token_key)?
.ok_or(ResponseError::invalid_token(format!(
"Api key does not exist: {}",
user_api_key
)))?;
if token_config.revoked {
return Err(ResponseError::invalid_token("token revoked"));
}
if let Some(index) = request_index {
if !token_config
.indexes
.iter()
.any(|r| match_wildcard(&r, &index))
{
return Err(ResponseError::invalid_token(
"token is not allowed to access to this index",
));
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(())
}
}
}
if token_config.expires_at < Utc::now() {
return Err(ResponseError::invalid_token("token expired"));
}
if token_config.acl.contains(&ACL::All) {
return Ok(());
}
if !token_config.acl.contains(&acl) {
return Err(ResponseError::invalid_token("no permission"));
}
Ok(())
}
fn header(&self, name: &str) -> SResult<String> {
let header = self
.headers()
.get(name)
.ok_or(ResponseError::missing_header(name))?
.to_str()
.map_err(|_| ResponseError::missing_header("X-Meili-API-Key"))?
.to_string();
Ok(header)
Err(ResponseError::InvalidToken(user_api_key.unwrap_or("Need a token").to_owned()))
}
fn url_param(&self, name: &str) -> SResult<String> {