Skip to content

Commit

Permalink
Merge #2173
Browse files Browse the repository at this point in the history
2173: chore(all): replace chrono with time r=irevoire a=irevoire

Chrono has been unmaintained for a few month now and there is a CVE on it.

Also I updated all the error messages related to the API key as you can see here: meilisearch/specifications#114

fix #2172

Co-authored-by: Irevoire <[email protected]>
  • Loading branch information
bors[bot] and irevoire authored Feb 17, 2022
2 parents cd6276e + 05c8d81 commit c3e3c90
Show file tree
Hide file tree
Showing 33 changed files with 369 additions and 226 deletions.
72 changes: 59 additions & 13 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion meilisearch-auth/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ edition = "2021"
enum-iterator = "0.7.0"
heed = { git = "https://github.com/Kerollmops/heed", tag = "v0.12.1" }
sha2 = "0.9.6"
chrono = { version = "0.4.19", features = ["serde"] }
meilisearch-error = { path = "../meilisearch-error" }
serde_json = { version = "1.0.67", features = ["preserve_order"] }
time = { version = "0.3.7", features = ["serde-well-known", "formatting", "parsing", "macros"] }
rand = "0.8.4"
serde = { version = "1.0.130", features = ["derive"] }
thiserror = "1.0.28"
8 changes: 4 additions & 4 deletions meilisearch-auth/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@ pub type Result<T> = std::result::Result<T, AuthControllerError>;
pub enum AuthControllerError {
#[error("`{0}` field is mandatory.")]
MissingParameter(&'static str),
#[error("actions field value `{0}` is invalid. It should be an array of string representing action names.")]
#[error("`actions` field value `{0}` is invalid. It should be an array of string representing action names.")]
InvalidApiKeyActions(Value),
#[error("indexes field value `{0}` is invalid. It should be an array of string representing index names.")]
#[error("`indexes` field value `{0}` is invalid. It should be an array of string representing index names.")]
InvalidApiKeyIndexes(Value),
#[error("expiresAt field value `{0}` is invalid. It should be in ISO-8601 format to represents a date or datetime in the future or specified as a null value. e.g. 'YYYY-MM-DD' or 'YYYY-MM-DDTHH:MM:SS'.")]
#[error("`expiresAt` field value `{0}` is invalid. It should follow the RFC 3339 format to represents a date or datetime in the future or specified as a null value. e.g. 'YYYY-MM-DD' or 'YYYY-MM-DD HH:MM:SS'.")]
InvalidApiKeyExpiresAt(Value),
#[error("description field value `{0}` is invalid. It should be a string or specified as a null value.")]
#[error("`description` field value `{0}` is invalid. It should be a string or specified as a null value.")]
InvalidApiKeyDescription(Value),
#[error("API key `{0}` not found.")]
ApiKeyNotFound(String),
Expand Down
57 changes: 38 additions & 19 deletions meilisearch-auth/src/key.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
use crate::action::Action;
use crate::error::{AuthControllerError, Result};
use crate::store::{KeyId, KEY_ID_LENGTH};
use chrono::{DateTime, NaiveDate, NaiveDateTime, Utc};
use rand::Rng;
use serde::{Deserialize, Serialize};
use serde_json::{from_value, Value};
use time::format_description::well_known::Rfc3339;
use time::macros::{format_description, time};
use time::{Date, OffsetDateTime, PrimitiveDateTime};

#[derive(Debug, Deserialize, Serialize)]
pub struct Key {
Expand All @@ -13,9 +15,12 @@ pub struct Key {
pub id: KeyId,
pub actions: Vec<Action>,
pub indexes: Vec<String>,
pub expires_at: Option<DateTime<Utc>>,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
#[serde(with = "time::serde::rfc3339::option")]
pub expires_at: Option<OffsetDateTime>,
#[serde(with = "time::serde::rfc3339")]
pub created_at: OffsetDateTime,
#[serde(with = "time::serde::rfc3339")]
pub updated_at: OffsetDateTime,
}

impl Key {
Expand Down Expand Up @@ -52,8 +57,8 @@ impl Key {
.map(parse_expiration_date)
.ok_or(AuthControllerError::MissingParameter("expiresAt"))??;

let created_at = Utc::now();
let updated_at = Utc::now();
let created_at = OffsetDateTime::now_utc();
let updated_at = created_at;

Ok(Self {
description,
Expand Down Expand Up @@ -89,24 +94,26 @@ impl Key {
self.expires_at = parse_expiration_date(exp)?;
}

self.updated_at = Utc::now();
self.updated_at = OffsetDateTime::now_utc();

Ok(())
}

pub(crate) fn default_admin() -> Self {
let now = OffsetDateTime::now_utc();
Self {
description: Some("Default Admin API Key (Use it for all other operations. Caution! Do not use it on a public frontend)".to_string()),
id: generate_id(),
actions: vec![Action::All],
indexes: vec!["*".to_string()],
expires_at: None,
created_at: Utc::now(),
updated_at: Utc::now(),
created_at: now,
updated_at: now,
}
}

pub(crate) fn default_search() -> Self {
let now = OffsetDateTime::now_utc();
Self {
description: Some(
"Default Search API Key (Use it to search from the frontend)".to_string(),
Expand All @@ -115,8 +122,8 @@ impl Key {
actions: vec![Action::Search],
indexes: vec!["*".to_string()],
expires_at: None,
created_at: Utc::now(),
updated_at: Utc::now(),
created_at: now,
updated_at: now,
}
}
}
Expand All @@ -134,22 +141,34 @@ fn generate_id() -> [u8; KEY_ID_LENGTH] {
bytes
}

fn parse_expiration_date(value: &Value) -> Result<Option<DateTime<Utc>>> {
fn parse_expiration_date(value: &Value) -> Result<Option<OffsetDateTime>> {
match value {
Value::String(string) => DateTime::parse_from_rfc3339(string)
.map(|d| d.into())
Value::String(string) => OffsetDateTime::parse(string, &Rfc3339)
.or_else(|_| {
NaiveDateTime::parse_from_str(string, "%Y-%m-%dT%H:%M:%S")
.map(|naive| DateTime::from_utc(naive, Utc))
PrimitiveDateTime::parse(
string,
format_description!(
"[year repr:full base:calendar]-[month repr:numerical]-[day]T[hour]:[minute]:[second]"
),
).map(|datetime| datetime.assume_utc())
})
.or_else(|_| {
NaiveDate::parse_from_str(string, "%Y-%m-%d")
.map(|naive| DateTime::from_utc(naive.and_hms(0, 0, 0), Utc))
PrimitiveDateTime::parse(
string,
format_description!(
"[year repr:full base:calendar]-[month repr:numerical]-[day] [hour]:[minute]:[second]"
),
).map(|datetime| datetime.assume_utc())
})
.or_else(|_| {
Date::parse(string, format_description!(
"[year repr:full base:calendar]-[month repr:numerical]-[day]"
)).map(|date| PrimitiveDateTime::new(date, time!(00:00)).assume_utc())
})
.map_err(|_| AuthControllerError::InvalidApiKeyExpiresAt(value.clone()))
// check if the key is already expired.
.and_then(|d| {
if d > Utc::now() {
if d > OffsetDateTime::now_utc() {
Ok(d)
} else {
Err(AuthControllerError::InvalidApiKeyExpiresAt(value.clone()))
Expand Down
4 changes: 2 additions & 2 deletions meilisearch-auth/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ use std::path::Path;
use std::str::from_utf8;
use std::sync::Arc;

use chrono::Utc;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use sha2::{Digest, Sha256};
use time::OffsetDateTime;

pub use action::{actions, Action};
use error::{AuthControllerError, Result};
Expand Down Expand Up @@ -148,7 +148,7 @@ impl AuthController {
None => self.store.prefix_first_expiration_date(key, action)?,
}) {
// check expiration date.
Some(Some(exp)) => Ok(Utc::now() < exp),
Some(Some(exp)) => Ok(OffsetDateTime::now_utc() < exp),
// no expiration date.
Some(None) => Ok(true),
// action or index forbidden.
Expand Down
Loading

0 comments on commit c3e3c90

Please sign in to comment.