summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock5
-rw-r--r--Cargo.toml4
-rw-r--r--src/api/auth/account.rs12
-rw-r--r--src/api/auth/device.rs17
-rw-r--r--src/api/auth/invite.rs4
-rw-r--r--src/api/auth/oauth.rs12
-rw-r--r--src/api/mod.rs22
-rw-r--r--src/db/mod.rs8
-rw-r--r--src/lib.rs2
-rw-r--r--src/types.rs16
-rw-r--r--tests/integration.rs6
11 files changed, 46 insertions, 62 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 8b2788b..a0445bf 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1448,7 +1448,6 @@ version = "0.1.0"
dependencies = [
"anyhow",
"base64",
- "chrono",
"dotenv",
"either",
"futures",
@@ -1469,6 +1468,7 @@ dependencies = [
"sha2 0.10.2",
"sqlx",
"subtle",
+ "time 0.3.11",
"url",
"validator",
"web-push",
@@ -2501,7 +2501,6 @@ dependencies = [
"bitflags",
"byteorder",
"bytes",
- "chrono",
"crc",
"crossbeam-queue",
"dirs",
@@ -2534,6 +2533,7 @@ dependencies = [
"sqlx-rt",
"stringprep",
"thiserror",
+ "time 0.3.11",
"tokio-stream",
"url",
"whoami",
@@ -2693,6 +2693,7 @@ dependencies = [
"itoa",
"libc",
"num_threads",
+ "serde",
"time-macros",
]
diff --git a/Cargo.toml b/Cargo.toml
index 9a67b16..239e1a0 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -8,7 +8,6 @@ edition = "2021"
[dependencies]
anyhow = "1.0"
base64 = "0.13"
-chrono = "0.4.19"
dotenv = "0.15"
either = "1.7"
futures = "0.3.21"
@@ -25,8 +24,9 @@ scrypt = { version = "0.10", features = [ "simple" ] }
serde = { version = "1.0", features = [ "derive" ] }
serde_json = "1.0"
sha2 = "0.10.2"
-sqlx = { version = "0.6.0", features = [ "runtime-tokio-native-tls", "postgres", "chrono", "json", "offline" ] }
+sqlx = { version = "0.6.0", features = [ "runtime-tokio-native-tls", "postgres", "time", "json", "offline" ] }
subtle = "2.4.1"
+time = { version = "0.3.11", features = [ "serde" ] }
url = "2.2.2"
validator = { version = "0.15", features = [ "derive" ] }
web-push = "0.9.2"
diff --git a/src/api/auth/account.rs b/src/api/auth/account.rs
index 8f3ac55..d96229d 100644
--- a/src/api/auth/account.rs
+++ b/src/api/auth/account.rs
@@ -1,13 +1,13 @@
use std::sync::Arc;
use anyhow::Result;
-use chrono::{DateTime, Utc};
use password_hash::SaltString;
use rand::{thread_rng, Rng};
use rocket::request::FromRequest;
use rocket::State;
use rocket::{serde::json::Json, Request};
use serde::{Deserialize, Serialize};
+use time::OffsetDateTime;
use validator::Validate;
use crate::api::{Empty, EMPTY};
@@ -19,7 +19,7 @@ use crate::types::{AccountResetID, HawkKey};
use crate::utils::DeferAction;
use crate::Config;
use crate::{
- api::{auth, serialize_dt},
+ api::auth,
auth::{AuthSource, Authenticated},
crypto::{AuthPW, KeyBundle, KeyFetchReq, SessionCredentials},
types::{KeyFetchID, OauthToken, SecretKey, User, UserID, VerifyHash},
@@ -56,8 +56,8 @@ pub(crate) struct CreateResp {
sessionToken: SessionToken,
#[serde(skip_serializing_if = "Option::is_none")]
keyFetchToken: Option<KeyFetchToken>,
- #[serde(serialize_with = "serialize_dt")]
- authAt: DateTime<Utc>,
+ #[serde(with = "time::serde::timestamp")]
+ authAt: OffsetDateTime,
// MISSING verificationMethod
}
@@ -165,8 +165,8 @@ pub(crate) struct LoginResp {
// NOTE this is the *account* verified status, not the session status.
// the spec doesn't say.
verified: bool,
- #[serde(serialize_with = "serialize_dt")]
- authAt: DateTime<Utc>,
+ #[serde(with = "time::serde::timestamp")]
+ authAt: OffsetDateTime,
// MISSING metricsEnabled
}
diff --git a/src/api/auth/device.rs b/src/api/auth/device.rs
index 44fbd2a..5201073 100644
--- a/src/api/auth/device.rs
+++ b/src/api/auth/device.rs
@@ -1,11 +1,11 @@
use std::time::Duration;
use std::{collections::HashMap, sync::Arc};
-use chrono::{DateTime, Utc};
use futures::future::join_all;
use rocket::{serde::json::Json, State};
use serde::{Deserialize, Serialize};
use serde_json::Value;
+use time::OffsetDateTime;
use crate::api::auth::{WithSession, WithVerifiedFxaLogin, WithVerifiedSession};
use crate::api::{Empty, EMPTY};
@@ -13,7 +13,7 @@ use crate::db::DbConn;
use crate::push::PushClient;
use crate::utils::DeferAction;
use crate::{
- api::{auth, serialize_dt_opt},
+ api::auth,
auth::Authenticated,
db::Db,
types::{
@@ -39,7 +39,8 @@ fn map_error(e: sqlx::Error) -> auth::Error {
pub(crate) struct Info {
isCurrentDevice: bool,
id: DeviceID,
- lastAccessTime: i64,
+ #[serde(with = "time::serde::timestamp")]
+ lastAccessTime: OffsetDateTime,
name: String,
r#type: String,
pushCallback: Option<String>,
@@ -62,7 +63,7 @@ fn device_to_json(current: Option<&DeviceID>, dev: Device) -> Info {
Info {
isCurrentDevice: Some(&dev.device_id) == current,
id: dev.device_id,
- lastAccessTime: dev.last_active.timestamp(),
+ lastAccessTime: dev.last_active,
name: dev.name,
r#type: dev.type_,
pushCallback: pcb,
@@ -356,11 +357,11 @@ pub(crate) struct AttachedClient {
isCurrentSession: bool,
deviceType: Option<String>,
name: Option<String>,
- #[serde(serialize_with = "serialize_dt_opt")]
- createdTime: Option<DateTime<Utc>>,
+ #[serde(with = "time::serde::timestamp::option")]
+ createdTime: Option<OffsetDateTime>,
// MISSING createdTimeFormatted
- #[serde(serialize_with = "serialize_dt_opt")]
- lastAccessTime: Option<DateTime<Utc>>,
+ #[serde(with = "time::serde::timestamp::option")]
+ lastAccessTime: Option<OffsetDateTime>,
// MISSING lastAccessTimeFormatted
// MISSING approximateLastAccessTime
// MISSING approximateLastAccessTimeFormatted
diff --git a/src/api/auth/invite.rs b/src/api/auth/invite.rs
index e70c3d6..ecd39f9 100644
--- a/src/api/auth/invite.rs
+++ b/src/api/auth/invite.rs
@@ -1,7 +1,7 @@
use base64::URL_SAFE_NO_PAD;
-use chrono::{Duration, Utc};
use rocket::{http::uri::Reference, serde::json::Json, State};
use serde::{Deserialize, Serialize};
+use time::{Duration, OffsetDateTime};
use crate::{api::auth, auth::Authenticated, crypto::random_bytes, db::DbConn, Config};
@@ -13,7 +13,7 @@ pub(crate) async fn generate_invite_link(
ttl: Duration,
) -> anyhow::Result<Reference<'static>> {
let code = base64::encode_config(&random_bytes::<32>(), URL_SAFE_NO_PAD);
- db.add_invite_code(&code, Utc::now() + ttl).await?;
+ db.add_invite_code(&code, OffsetDateTime::now_utc() + ttl).await?;
Reference::parse_owned(format!("{}/#/register/{}", cfg.location, code))
.map_err(|e| anyhow!("url building failed at {e}"))
}
diff --git a/src/api/auth/oauth.rs b/src/api/auth/oauth.rs
index 384d4b4..25d6150 100644
--- a/src/api/auth/oauth.rs
+++ b/src/api/auth/oauth.rs
@@ -1,11 +1,11 @@
use std::collections::HashMap;
-use chrono::{DateTime, Duration, Local, Utc};
use rocket::serde::json::Json;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use sha2::Digest;
use subtle::ConstantTimeEq;
+use time::{Duration, OffsetDateTime};
use crate::api::auth::WithVerifiedFxaLogin;
use crate::api::{Empty, EMPTY};
@@ -13,7 +13,7 @@ use crate::crypto::SessionToken;
use crate::db::DbConn;
use crate::types::oauth::{Scope, ScopeSet};
use crate::{
- api::{auth, serialize_dt},
+ api::auth,
auth::Authenticated,
crypto::SessionCredentials,
types::{
@@ -283,8 +283,8 @@ pub(crate) struct TokenResp {
scope: ScopeSet,
token_type: TokenType,
expires_in: u32,
- #[serde(serialize_with = "serialize_dt")]
- auth_at: DateTime<Utc>,
+ #[serde(with = "time::serde::timestamp")]
+ auth_at: OffsetDateTime,
#[serde(skip_serializing_if = "Option::is_none")]
keys_jwe: Option<String>,
}
@@ -328,7 +328,7 @@ pub(crate) async fn token_unauthenticated(
async fn token_impl(
db: &DbConn,
user_id: Option<UserID>,
- auth_at: Option<DateTime<Utc>>,
+ auth_at: Option<OffsetDateTime>,
req: TokenReq,
parent_refresh: Option<OauthTokenID>,
parent_session: Option<SessionID>,
@@ -385,7 +385,7 @@ async fn token_impl(
scope: scope.clone(),
parent_refresh,
parent_session,
- expires_at: (Local::now() + Duration::seconds(ttl.into())).into(),
+ expires_at: OffsetDateTime::now_utc() + Duration::seconds(ttl.into()),
},
)
.await?;
diff --git a/src/api/mod.rs b/src/api/mod.rs
index 1831659..d5997dc 100644
--- a/src/api/mod.rs
+++ b/src/api/mod.rs
@@ -1,30 +1,10 @@
-use chrono::{DateTime, TimeZone};
use rocket::serde::json::Json;
-use serde::{Deserialize, Serialize, Serializer};
+use serde::{Deserialize, Serialize};
pub(crate) mod auth;
pub(crate) mod oauth;
pub(crate) mod profile;
-pub fn serialize_dt<S, TZ>(dt: &DateTime<TZ>, ser: S) -> Result<S::Ok, S::Error>
-where
- S: Serializer,
- TZ: TimeZone,
-{
- ser.serialize_i64(dt.timestamp())
-}
-
-pub fn serialize_dt_opt<S, TZ>(dt: &Option<DateTime<TZ>>, ser: S) -> Result<S::Ok, S::Error>
-where
- S: Serializer,
- TZ: TimeZone,
-{
- match dt {
- Some(dt) => serialize_dt(dt, ser),
- None => ser.serialize_unit(),
- }
-}
-
#[derive(Clone, Copy, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Empty {}
diff --git a/src/db/mod.rs b/src/db/mod.rs
index 6cea895..d9a114e 100644
--- a/src/db/mod.rs
+++ b/src/db/mod.rs
@@ -1,7 +1,6 @@
use std::{error::Error, mem::replace, sync::Arc};
use anyhow::Result;
-use chrono::{DateTime, Duration, Utc};
use password_hash::SaltString;
use rocket::{
fairing::{self, Fairing},
@@ -12,6 +11,7 @@ use rocket::{
};
use serde_json::Value;
use sqlx::{query, query_as, query_scalar, PgPool, Postgres, Transaction};
+use time::{Duration, OffsetDateTime};
use crate::{
crypto::WrappedKeyBundle,
@@ -198,7 +198,7 @@ impl DbConn {
key: HawkKey,
verified: bool,
verify_code: Option<&str>,
- ) -> sqlx::Result<DateTime<Utc>> {
+ ) -> sqlx::Result<OffsetDateTime> {
query_scalar!(
r#"insert into user_session (session_id, user_id, req_hmac_key, device_id, verified,
verify_code)
@@ -313,7 +313,7 @@ impl DbConn {
payload: &Value,
ttl: u32,
) -> sqlx::Result<i64> {
- let expires = Utc::now() + Duration::seconds(ttl as i64);
+ let expires = OffsetDateTime::now_utc() + Duration::seconds(ttl as i64);
query!(
r#"insert into device_commands (device_id, command, payload, expires, sender)
values ($1, $2, $3, $4, $5)
@@ -989,7 +989,7 @@ impl DbConn {
//
//
- pub async fn add_invite_code(&self, code: &str, expires: DateTime<Utc>) -> sqlx::Result<()> {
+ pub async fn add_invite_code(&self, code: &str, expires: OffsetDateTime) -> sqlx::Result<()> {
query!(r#"insert into invite_codes (code, expires_at) values ($1, $2)"#, code, expires,)
.execute(&mut self.get().await?.tx)
.await?;
diff --git a/src/lib.rs b/src/lib.rs
index 29f3e08..d783c6d 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -5,7 +5,6 @@ use std::{
};
use anyhow::Context;
-use chrono::Duration;
use db::Db;
use futures::Future;
use lettre::message::Mailbox;
@@ -24,6 +23,7 @@ use rocket::{
Request, State,
};
use serde_json::{json, Value};
+use time::Duration;
use utils::DeferredActions;
use crate::api::auth::invite::generate_invite_link;
diff --git a/src/types.rs b/src/types.rs
index 7699483..64b35a1 100644
--- a/src/types.rs
+++ b/src/types.rs
@@ -1,4 +1,3 @@
-use chrono::{DateTime, Utc};
use password_hash::{rand_core::OsRng, Output, SaltString};
use rand::RngCore;
use serde::{Deserialize, Serialize};
@@ -14,6 +13,7 @@ use std::{
ops::Deref,
str::FromStr,
};
+use time::OffsetDateTime;
use self::oauth::ScopeSet;
@@ -271,7 +271,7 @@ pub(crate) struct UserSession {
pub(crate) uid: UserID,
pub(crate) req_hmac_key: HawkKey,
pub(crate) device_id: Option<DeviceID>,
- pub(crate) created_at: DateTime<Utc>,
+ pub(crate) created_at: OffsetDateTime,
pub(crate) verified: bool,
pub(crate) verify_code: Option<String>,
}
@@ -282,7 +282,7 @@ pub(crate) struct DeviceCommand {
pub(crate) command: String,
pub(crate) payload: Value,
#[allow(dead_code)]
- pub(crate) expires: DateTime<Utc>,
+ pub(crate) expires: OffsetDateTime,
// NOTE this is a device ID, but we don't link it to the actual sender device
// because removing a device would also remove its queued commands. this mirrors
// what fxa does.
@@ -332,7 +332,7 @@ impl Deref for DeviceCommands {
pub(crate) struct Device {
pub(crate) device_id: DeviceID,
// taken from session, otherwise UNIX_EPOCH
- pub(crate) last_active: DateTime<Utc>,
+ pub(crate) last_active: OffsetDateTime,
pub(crate) name: String,
pub(crate) type_: String,
pub(crate) push: Option<DevicePush>,
@@ -367,7 +367,7 @@ pub(crate) struct OauthAccessToken {
pub(crate) scope: ScopeSet,
pub(crate) parent_refresh: Option<OauthTokenID>,
pub(crate) parent_session: Option<SessionID>,
- pub(crate) expires_at: DateTime<Utc>,
+ pub(crate) expires_at: OffsetDateTime,
}
#[derive(Debug)]
@@ -386,7 +386,7 @@ pub(crate) struct OauthAuthorization {
pub(crate) access_type: OauthAccessType,
pub(crate) code_challenge: String,
pub(crate) keys_jwe: Option<String>,
- pub(crate) auth_at: DateTime<Utc>,
+ pub(crate) auth_at: OffsetDateTime,
}
#[derive(Debug)]
@@ -418,8 +418,8 @@ pub(crate) struct AttachedClient {
pub(crate) refresh_token_id: Option<OauthTokenID>,
pub(crate) device_type: Option<String>,
pub(crate) name: Option<String>,
- pub(crate) created_time: Option<DateTime<Utc>>,
- pub(crate) last_access_time: Option<DateTime<Utc>>,
+ pub(crate) created_time: Option<OffsetDateTime>,
+ pub(crate) last_access_time: Option<OffsetDateTime>,
pub(crate) scope: Option<String>,
}
diff --git a/tests/integration.rs b/tests/integration.rs
index 1866702..99c7a4f 100644
--- a/tests/integration.rs
+++ b/tests/integration.rs
@@ -2,7 +2,6 @@ use std::env;
use anyhow::Context;
use base64::URL_SAFE_NO_PAD;
-use chrono::{Duration, Utc};
use futures::channel::oneshot::channel;
use minor_skulk::{build, db::Db};
use password_hash::rand_core::OsRng;
@@ -11,6 +10,7 @@ use rocket::{
fairing::AdHoc,
tokio::{process::Command, spawn},
};
+use time::{Duration, OffsetDateTime};
#[macro_use]
extern crate rocket;
@@ -54,7 +54,9 @@ async fn run_pytest(
let mut code = [0; 32];
OsRng.fill_bytes(&mut code);
let code = base64::encode_config(code, URL_SAFE_NO_PAD);
- tx.add_invite_code(&code, Utc::now() + Duration::minutes(5)).await.unwrap();
+ tx.add_invite_code(&code, OffsetDateTime::now_utc() + Duration::minutes(5))
+ .await
+ .unwrap();
tx.commit().await.unwrap();
env::set_var("INVITE_CODE", code);
}