Fix PR comments

This commit is contained in:
ManyTheFish 2022-06-01 18:06:20 +02:00
parent 7652295d2c
commit 4512eed8f5
7 changed files with 29 additions and 19 deletions

View File

@ -4,6 +4,7 @@ version = "0.27.1"
edition = "2021" edition = "2021"
[dependencies] [dependencies]
base64 = "0.13.0"
enum-iterator = "0.7.0" enum-iterator = "0.7.0"
meilisearch-error = { path = "../meilisearch-error" } meilisearch-error = { path = "../meilisearch-error" }
milli = { git = "https://github.com/meilisearch/milli.git", tag = "v0.28.0" } milli = { git = "https://github.com/meilisearch/milli.git", tag = "v0.28.0" }
@ -11,7 +12,6 @@ rand = "0.8.4"
serde = { version = "1.0.136", features = ["derive"] } serde = { version = "1.0.136", features = ["derive"] }
serde_json = { version = "1.0.79", features = ["preserve_order"] } serde_json = { version = "1.0.79", features = ["preserve_order"] }
sha2 = "0.10.2" sha2 = "0.10.2"
base64 = "0.13.0"
thiserror = "1.0.30" thiserror = "1.0.30"
time = { version = "0.3.7", features = ["serde-well-known", "formatting", "parsing", "macros"] } time = { version = "0.3.7", features = ["serde-well-known", "formatting", "parsing", "macros"] }
uuid = { version = "0.8.2", features = ["serde", "v4"] } uuid = { version = "0.8.2", features = ["serde", "v4"] }

View File

@ -133,7 +133,7 @@ impl Key {
let uid = Uuid::new_v4(); let uid = Uuid::new_v4();
Self { Self {
name: Some("Default Admin API Key".to_string()), name: Some("Default Admin API Key".to_string()),
description: Some("Use it for all other than search operations. Caution! Do not expose it on a public frontend".to_string()), description: Some("Use it for anything that is not a search operation. Caution! Do not expose it on a public frontend".to_string()),
uid, uid,
actions: vec![Action::All], actions: vec![Action::All],
indexes: vec!["*".to_string()], indexes: vec!["*".to_string()],

View File

@ -4,20 +4,19 @@ pub mod error;
mod key; mod key;
mod store; mod store;
use crate::store::generate_key;
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use std::path::Path; use std::path::Path;
use std::sync::Arc; use std::sync::Arc;
use uuid::Uuid;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_json::Value; use serde_json::Value;
use time::OffsetDateTime; use time::OffsetDateTime;
use uuid::Uuid;
pub use action::{actions, Action}; pub use action::{actions, Action};
use error::{AuthControllerError, Result}; use error::{AuthControllerError, Result};
pub use key::Key; pub use key::Key;
use store::generate_key_as_base64;
pub use store::open_auth_store_env; pub use store::open_auth_store_env;
use store::HeedAuthStore; use store::HeedAuthStore;
@ -63,16 +62,18 @@ impl AuthController {
.ok_or_else(|| AuthControllerError::ApiKeyNotFound(uid.to_string())) .ok_or_else(|| AuthControllerError::ApiKeyNotFound(uid.to_string()))
} }
pub fn get_optional_uid_from_sha(&self, sha: &[u8]) -> Result<Option<Uuid>> { pub fn get_optional_uid_from_encoded_key(&self, encoded_key: &[u8]) -> Result<Option<Uuid>> {
match &self.master_key { match &self.master_key {
Some(master_key) => self.store.get_uid_from_sha(sha, master_key.as_bytes()), Some(master_key) => self
.store
.get_uid_from_encoded_key(encoded_key, master_key.as_bytes()),
None => Ok(None), None => Ok(None),
} }
} }
pub fn get_uid_from_sha(&self, sha: &str) -> Result<Uuid> { pub fn get_uid_from_encoded_key(&self, encoded_key: &str) -> Result<Uuid> {
self.get_optional_uid_from_sha(sha.as_bytes())? self.get_optional_uid_from_encoded_key(encoded_key.as_bytes())?
.ok_or_else(|| AuthControllerError::ApiKeyNotFound(sha.to_string())) .ok_or_else(|| AuthControllerError::ApiKeyNotFound(encoded_key.to_string()))
} }
pub fn get_key_filters( pub fn get_key_filters(
@ -134,7 +135,7 @@ impl AuthController {
pub fn generate_key(&self, uid: Uuid) -> Option<String> { pub fn generate_key(&self, uid: Uuid) -> Option<String> {
self.master_key self.master_key
.as_ref() .as_ref()
.map(|master_key| generate_key(uid.as_bytes(), master_key.as_bytes())) .map(|master_key| generate_key_as_base64(uid.as_bytes(), master_key.as_bytes()))
} }
/// Check if the provided key is authorized to make a specific action /// Check if the provided key is authorized to make a specific action

View File

@ -118,14 +118,20 @@ impl HeedAuthStore {
self.keys.get(&rtxn, uid.as_bytes()).map_err(|e| e.into()) self.keys.get(&rtxn, uid.as_bytes()).map_err(|e| e.into())
} }
pub fn get_uid_from_sha(&self, key_sha: &[u8], master_key: &[u8]) -> Result<Option<Uuid>> { pub fn get_uid_from_encoded_key(
&self,
encoded_key: &[u8],
master_key: &[u8],
) -> Result<Option<Uuid>> {
let rtxn = self.env.read_txn()?; let rtxn = self.env.read_txn()?;
let uid = self let uid = self
.keys .keys
.remap_data_type::<DecodeIgnore>() .remap_data_type::<DecodeIgnore>()
.iter(&rtxn)? .iter(&rtxn)?
.filter_map(|res| match res { .filter_map(|res| match res {
Ok((uid, _)) if generate_key(uid, master_key).as_bytes() == key_sha => { Ok((uid, _))
if generate_key_as_base64(uid, master_key).as_bytes() == encoded_key =>
{
let (uid, _) = try_split_array_at(uid)?; let (uid, _) = try_split_array_at(uid)?;
Some(Uuid::from_bytes(*uid)) Some(Uuid::from_bytes(*uid))
} }
@ -235,7 +241,7 @@ impl<'a> milli::heed::BytesEncode<'a> for KeyIdActionCodec {
} }
} }
pub fn generate_key(uid: &[u8], master_key: &[u8]) -> String { pub fn generate_key_as_base64(uid: &[u8], master_key: &[u8]) -> String {
let key = [uid, master_key].concat(); let key = [uid, master_key].concat();
let sha = Sha256::digest(&key); let sha = Sha256::digest(&key);
base64::encode_config(sha, base64::URL_SAFE_NO_PAD) base64::encode_config(sha, base64::URL_SAFE_NO_PAD)

View File

@ -188,7 +188,7 @@ pub mod policies {
return Some(filters); return Some(filters);
} else if let Some(action) = Action::from_repr(A) { } else if let Some(action) = Action::from_repr(A) {
// API key // API key
if let Ok(Some(uid)) = auth.get_optional_uid_from_sha(token.as_bytes()) { if let Ok(Some(uid)) = auth.get_optional_uid_from_encoded_key(token.as_bytes()) {
if let Ok(true) = auth.is_key_authorized(uid, action, index) { if let Ok(true) = auth.is_key_authorized(uid, action, index) {
return auth.get_key_filters(uid, None).ok(); return auth.get_key_filters(uid, None).ok();
} }

View File

@ -69,7 +69,8 @@ pub async fn get_api_key(
let key = path.into_inner().key; let key = path.into_inner().key;
let res = tokio::task::spawn_blocking(move || -> Result<_, AuthControllerError> { let res = tokio::task::spawn_blocking(move || -> Result<_, AuthControllerError> {
let uid = Uuid::parse_str(&key).or_else(|_| auth_controller.get_uid_from_sha(&key))?; let uid =
Uuid::parse_str(&key).or_else(|_| auth_controller.get_uid_from_encoded_key(&key))?;
let key = auth_controller.get_key(uid)?; let key = auth_controller.get_key(uid)?;
Ok(KeyView::from_key(key, &auth_controller)) Ok(KeyView::from_key(key, &auth_controller))
@ -88,7 +89,8 @@ pub async fn patch_api_key(
let key = path.into_inner().key; let key = path.into_inner().key;
let body = body.into_inner(); let body = body.into_inner();
let res = tokio::task::spawn_blocking(move || -> Result<_, AuthControllerError> { let res = tokio::task::spawn_blocking(move || -> Result<_, AuthControllerError> {
let uid = Uuid::parse_str(&key).or_else(|_| auth_controller.get_uid_from_sha(&key))?; let uid =
Uuid::parse_str(&key).or_else(|_| auth_controller.get_uid_from_encoded_key(&key))?;
let key = auth_controller.update_key(uid, body)?; let key = auth_controller.update_key(uid, body)?;
Ok(KeyView::from_key(key, &auth_controller)) Ok(KeyView::from_key(key, &auth_controller))
@ -105,7 +107,8 @@ pub async fn delete_api_key(
) -> Result<HttpResponse, ResponseError> { ) -> Result<HttpResponse, ResponseError> {
let key = path.into_inner().key; let key = path.into_inner().key;
tokio::task::spawn_blocking(move || { tokio::task::spawn_blocking(move || {
let uid = Uuid::parse_str(&key).or_else(|_| auth_controller.get_uid_from_sha(&key))?; let uid =
Uuid::parse_str(&key).or_else(|_| auth_controller.get_uid_from_encoded_key(&key))?;
auth_controller.delete_key(uid) auth_controller.delete_key(uid)
}) })
.await .await

View File

@ -711,7 +711,7 @@ async fn list_api_keys() {
}, },
{ {
"name": "Default Admin API Key", "name": "Default Admin API Key",
"description": "Use it for all other than search operations. Caution! Do not expose it on a public frontend", "description": "Use it for anything that is not a search operation. Caution! Do not expose it on a public frontend",
"indexes": ["*"], "indexes": ["*"],
"actions": ["*"], "actions": ["*"],
"expiresAt": serde_json::Value::Null, "expiresAt": serde_json::Value::Null,