diff --git a/crates/dump/src/lib.rs b/crates/dump/src/lib.rs index 285818a87..0006baaa5 100644 --- a/crates/dump/src/lib.rs +++ b/crates/dump/src/lib.rs @@ -419,6 +419,7 @@ pub(crate) mod test { uid: Uuid::from_str("9f8a34da-b6b2-42f0-939b-dbd4c3448655").unwrap(), actions: vec![Action::DocumentsAll], indexes: vec![IndexUidPattern::from_str("doggos").unwrap()], + chats: vec![IndexUidPattern::from_str("OpenAI").unwrap()], expires_at: Some(datetime!(4130-03-14 12:21 UTC)), created_at: datetime!(1960-11-15 0:00 UTC), updated_at: datetime!(2022-11-10 0:00 UTC), @@ -429,6 +430,7 @@ pub(crate) mod test { uid: Uuid::from_str("4622f717-1c00-47bb-a494-39d76a49b591").unwrap(), actions: vec![Action::All], indexes: vec![IndexUidPattern::all()], + chats: vec![IndexUidPattern::all()], expires_at: None, created_at: datetime!(0000-01-01 00:01 UTC), updated_at: datetime!(1964-05-04 17:25 UTC), @@ -439,6 +441,7 @@ pub(crate) mod test { uid: Uuid::from_str("fb80b58b-0a34-412f-8ba7-1ce868f8ac5c").unwrap(), actions: vec![], indexes: vec![], + chats: vec![], expires_at: None, created_at: datetime!(400-02-29 0:00 UTC), updated_at: datetime!(1024-02-29 0:00 UTC), diff --git a/crates/dump/src/reader/compat/v5_to_v6.rs b/crates/dump/src/reader/compat/v5_to_v6.rs index f7bda81c6..23de9968d 100644 --- a/crates/dump/src/reader/compat/v5_to_v6.rs +++ b/crates/dump/src/reader/compat/v5_to_v6.rs @@ -187,6 +187,7 @@ impl CompatV5ToV6 { v5::StarOr::Other(uid) => v6::IndexUidPattern::new_unchecked(uid.as_str()), }) .collect(), + chats: vec![], expires_at: key.expires_at, created_at: key.created_at, updated_at: key.updated_at, diff --git a/crates/meilisearch-types/src/error.rs b/crates/meilisearch-types/src/error.rs index 11bad977d..3e502f169 100644 --- a/crates/meilisearch-types/src/error.rs +++ b/crates/meilisearch-types/src/error.rs @@ -390,6 +390,7 @@ InvalidDocumentEditionFunctionFilter , InvalidRequest , BAD_REQU EditDocumentsByFunctionError , InvalidRequest , BAD_REQUEST ; InvalidSettingsIndexChat , InvalidRequest , BAD_REQUEST ; // Experimental features - Chat Completions +InvalidApiKeyChats , InvalidRequest , BAD_REQUEST ; ChatWorkspaceNotFound , InvalidRequest , NOT_FOUND ; InvalidChatCompletionSource , InvalidRequest , BAD_REQUEST ; InvalidChatCompletionBaseApi , InvalidRequest , BAD_REQUEST ; diff --git a/crates/meilisearch-types/src/keys.rs b/crates/meilisearch-types/src/keys.rs index 432692c9e..ccc5a0615 100644 --- a/crates/meilisearch-types/src/keys.rs +++ b/crates/meilisearch-types/src/keys.rs @@ -57,6 +57,10 @@ pub struct CreateApiKey { #[deserr(error = DeserrJsonError, missing_field_error = DeserrJsonError::missing_api_key_indexes)] #[schema(value_type = Vec, example = json!(["products"]))] pub indexes: Vec, + /// A list of accessible chats permitted for the key. `["*"]` for all chats. The `*` character can be used as a wildcard when located at the last position. e.g. `chats_*` to allow access to all indexes whose names start with `chats_`. + #[deserr(default, error = DeserrJsonError)] + #[schema(value_type = Vec, example = json!(["OpenAI", "ChatGPT"]))] + pub chats: Vec, /// Represent the expiration date and time as RFC 3339 format. `null` equals to no expiration time. #[deserr(error = DeserrJsonError, try_from(Option) = parse_expiration_date -> ParseOffsetDateTimeError, missing_field_error = DeserrJsonError::missing_api_key_expires_at)] pub expires_at: Option, @@ -64,7 +68,7 @@ pub struct CreateApiKey { impl CreateApiKey { pub fn to_key(self) -> Key { - let CreateApiKey { description, name, uid, actions, indexes, expires_at } = self; + let CreateApiKey { description, name, uid, actions, indexes, chats, expires_at } = self; let now = OffsetDateTime::now_utc(); Key { description, @@ -72,6 +76,7 @@ impl CreateApiKey { uid, actions, indexes, + chats, expires_at, created_at: now, updated_at: now, @@ -120,6 +125,7 @@ pub struct Key { pub uid: KeyId, pub actions: Vec, pub indexes: Vec, + pub chats: Vec, #[serde(with = "time::serde::rfc3339::option")] pub expires_at: Option, #[serde(with = "time::serde::rfc3339")] @@ -138,6 +144,7 @@ impl Key { uid, actions: vec![Action::All], indexes: vec![IndexUidPattern::all()], + chats: vec![IndexUidPattern::all()], expires_at: None, created_at: now, updated_at: now, @@ -153,6 +160,7 @@ impl Key { uid, actions: vec![Action::Search], indexes: vec![IndexUidPattern::all()], + chats: vec![], expires_at: None, created_at: now, updated_at: now, @@ -168,6 +176,7 @@ impl Key { uid, actions: vec![Action::ChatCompletions, Action::Search], indexes: vec![IndexUidPattern::all()], + chats: vec![IndexUidPattern::all()], expires_at: None, created_at: now, updated_at: now, diff --git a/crates/meilisearch/src/extractors/authentication/mod.rs b/crates/meilisearch/src/extractors/authentication/mod.rs index 86614f153..745c4e7da 100644 --- a/crates/meilisearch/src/extractors/authentication/mod.rs +++ b/crates/meilisearch/src/extractors/authentication/mod.rs @@ -165,16 +165,22 @@ pub mod policies { ExpiredTenantToken { exp: i64, now: i64 }, #[error("The provided API key is invalid.")] InvalidApiKey, - #[error("The provided tenant token cannot acces the index `{index}`, allowed indexes are {allowed:?}.")] + #[error("The provided tenant token cannot access the index `{index}`, allowed indexes are {allowed:?}.")] TenantTokenAccessingnUnauthorizedIndex { index: String, allowed: Vec }, #[error( - "The API key used to generate this tenant token cannot acces the index `{index}`." + "The API key used to generate this tenant token cannot access the index `{index}`." )] TenantTokenApiKeyAccessingnUnauthorizedIndex { index: String }, #[error( - "The API key cannot acces the index `{index}`, authorized indexes are {allowed:?}." + "The API key cannot access the index `{index}`, authorized indexes are {allowed:?}." )] ApiKeyAccessingnUnauthorizedIndex { index: String, allowed: Vec }, + #[error("The provided tenant token cannot access the chats `{chat}`, allowed chats are {allowed:?}.")] + TenantTokenAccessingnUnauthorizedChat { chat: String, allowed: Vec }, + #[error("The API key used to generate this tenant token cannot access the chat `{chat}`.")] + TenantTokenApiKeyAccessingnUnauthorizedChat { chat: String }, + #[error("The API key cannot access the chat `{chat}`, authorized chats are {allowed:?}.")] + ApiKeyAccessingnUnauthorizedChat { chat: String, allowed: Vec }, #[error("The provided tenant token is invalid.")] InvalidTenantToken, #[error("Could not decode tenant token, {0}.")] @@ -231,8 +237,8 @@ pub mod policies { pub struct ActionPolicy; impl Policy for ActionPolicy { - /// Attempts to grant authentication from a bearer token (that can be a tenant token or an API key), the requested Action, - /// and a list of requested indexes. + /// Attempts to grant authentication from a bearer token (that can be a tenant token or an API key), + /// the requested Action, and a list of requested indexes. /// /// If the bearer token is not allowed for the specified indexes and action, returns `None`. /// Otherwise, returns an object containing the generated permissions: the search filters to add to a search, and the list of allowed indexes