summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorConrad Ludgate <conradludgate@gmail.com>2021-05-09 21:17:24 +0100
committerGitHub <noreply@github.com>2021-05-09 21:17:24 +0100
commitde2e34ac500c17e80fe4dcf2ed1c08add8998fa3 (patch)
treeaca08817ace6e0bd6a7dfc21615b2ed8b62f3a05
parente43e5ce74a85d87a625295b9b089a1b5b8e26fab (diff)
some changes :shrug: (#83)
* make everything a cow * fmt + clippy
-rw-r--r--atuin-client/src/api_client.rs90
-rw-r--r--atuin-client/src/lib.rs2
-rw-r--r--atuin-client/src/sync.rs12
-rw-r--r--atuin-common/src/api.rs62
-rw-r--r--atuin-common/src/lib.rs3
-rw-r--r--atuin-server/src/database.rs36
-rw-r--r--atuin-server/src/handlers/history.rs20
-rw-r--r--atuin-server/src/handlers/user.rs36
-rw-r--r--atuin-server/src/lib.rs2
-rw-r--r--atuin-server/src/models.rs18
-rw-r--r--src/command/login.rs9
11 files changed, 134 insertions, 156 deletions
diff --git a/atuin-client/src/api_client.rs b/atuin-client/src/api_client.rs
index a8ce7b27..4b0c98c7 100644
--- a/atuin-client/src/api_client.rs
+++ b/atuin-client/src/api_client.rs
@@ -7,21 +7,21 @@ use reqwest::{StatusCode, Url};
use sodiumoxide::crypto::secretbox;
use atuin_common::api::{
- AddHistoryRequest, CountResponse, LoginResponse, RegisterResponse, SyncHistoryResponse,
+ AddHistoryRequest, CountResponse, LoginRequest, LoginResponse, RegisterResponse,
+ SyncHistoryResponse,
};
use atuin_common::utils::hash_str;
-use crate::encryption::{decode_key, decrypt};
+use crate::encryption::{decode_key, decrypt, EncryptedHistory};
use crate::history::History;
-const VERSION: &str = env!("CARGO_PKG_VERSION");
+static APP_USER_AGENT: &str = concat!("atuin/", env!("CARGO_PKG_VERSION"),);
// TODO: remove all references to the encryption key from this
// It should be handled *elsewhere*
pub struct Client<'a> {
sync_addr: &'a str,
- token: &'a str,
key: secretbox::Key,
client: reqwest::Client,
}
@@ -31,7 +31,7 @@ pub fn register(
username: &str,
email: &str,
password: &str,
-) -> Result<RegisterResponse> {
+) -> Result<RegisterResponse<'static>> {
let mut map = HashMap::new();
map.insert("username", username);
map.insert("email", email);
@@ -48,7 +48,7 @@ pub fn register(
let client = reqwest::blocking::Client::new();
let resp = client
.post(url)
- .header(USER_AGENT, format!("atuin/{}", VERSION))
+ .header(USER_AGENT, APP_USER_AGENT)
.json(&map)
.send()?;
@@ -60,18 +60,14 @@ pub fn register(
Ok(session)
}
-pub fn login(address: &str, username: &str, password: &str) -> Result<LoginResponse> {
- let mut map = HashMap::new();
- map.insert("username", username);
- map.insert("password", password);
-
+pub fn login(address: &str, req: LoginRequest) -> Result<LoginResponse<'static>> {
let url = format!("{}/login", address);
let client = reqwest::blocking::Client::new();
let resp = client
.post(url)
- .header(USER_AGENT, format!("atuin/{}", VERSION))
- .json(&map)
+ .header(USER_AGENT, APP_USER_AGENT)
+ .json(&req)
.send()?;
if resp.status() != reqwest::StatusCode::OK {
@@ -83,31 +79,25 @@ pub fn login(address: &str, username: &str, password: &str) -> Result<LoginRespo
}
impl<'a> Client<'a> {
- pub fn new(sync_addr: &'a str, token: &'a str, key: String) -> Result<Self> {
+ pub fn new(sync_addr: &'a str, session_token: &'a str, key: String) -> Result<Self> {
+ let mut headers = HeaderMap::new();
+ headers.insert(AUTHORIZATION, format!("Token {}", session_token).parse()?);
+
Ok(Client {
sync_addr,
- token,
key: decode_key(key)?,
- client: reqwest::Client::new(),
+ client: reqwest::Client::builder()
+ .user_agent(APP_USER_AGENT)
+ .default_headers(headers)
+ .build()?,
})
}
pub async fn count(&self) -> Result<i64> {
let url = format!("{}/sync/count", self.sync_addr);
let url = Url::parse(url.as_str())?;
- let token = format!("Token {}", self.token);
- let token = token.parse()?;
- let mut headers = HeaderMap::new();
- headers.insert(AUTHORIZATION, token);
-
- let resp = self
- .client
- .get(url)
- .header(USER_AGENT, format!("atuin/{}", VERSION))
- .headers(headers)
- .send()
- .await?;
+ let resp = self.client.get(url).send().await?;
if resp.status() != StatusCode::OK {
return Err(eyre!("failed to get count (are you logged in?)"));
@@ -137,13 +127,7 @@ impl<'a> Client<'a> {
host,
);
- let resp = self
- .client
- .get(url)
- .header(AUTHORIZATION, format!("Token {}", self.token))
- .header(USER_AGENT, format!("atuin/{}", VERSION))
- .send()
- .await?;
+ let resp = self.client.get(url).send().await?;
let history = resp.json::<SyncHistoryResponse>().await?;
let history = history
@@ -156,41 +140,15 @@ impl<'a> Client<'a> {
Ok(history)
}
- pub async fn post_history(&self, history: &[AddHistoryRequest]) -> Result<()> {
+ pub async fn post_history(
+ &self,
+ history: &[AddHistoryRequest<'_, EncryptedHistory>],
+ ) -> Result<()> {
let url = format!("{}/history", self.sync_addr);
let url = Url::parse(url.as_str())?;
- self.client
- .post(url)
- .json(history)
- .header(AUTHORIZATION, format!("Token {}", self.token))
- .header(USER_AGENT, format!("atuin/{}", VERSION))
- .send()
- .await?;
+ self.client.post(url).json(history).send().await?;
Ok(())
}
-
- pub async fn login(&self, username: &str, password: &str) -> Result<LoginResponse> {
- let mut map = HashMap::new();
- map.insert("username", username);
- map.insert("password", password);
-
- let url = format!("{}/login", self.sync_addr);
- let resp = self
- .client
- .post(url)
- .json(&map)
- .header(USER_AGENT, format!("atuin/{}", VERSION))
- .send()
- .await?;
-
- if resp.status() != reqwest::StatusCode::OK {
- return Err(eyre!("invalid login details"));
- }
-
- let session = resp.json::<LoginResponse>().await?;
-
- Ok(session)
- }
}
diff --git a/atuin-client/src/lib.rs b/atuin-client/src/lib.rs
index 1207bfdb..82f19b52 100644
--- a/atuin-client/src/lib.rs
+++ b/atuin-client/src/lib.rs
@@ -1,3 +1,5 @@
+#![forbid(unsafe_code)]
+
#[macro_use]
extern crate log;
diff --git a/atuin-client/src/sync.rs b/atuin-client/src/sync.rs
index 5c6405df..16524fc6 100644
--- a/atuin-client/src/sync.rs
+++ b/atuin-client/src/sync.rs
@@ -99,7 +99,7 @@ async fn sync_upload(
while local_count > remote_count {
let last = db.before(cursor, HISTORY_PAGE_SIZE).await?;
- let mut buffer = Vec::<AddHistoryRequest>::new();
+ let mut buffer = Vec::new();
if last.is_empty() {
break;
@@ -107,13 +107,11 @@ async fn sync_upload(
for i in last {
let data = encrypt(&i, &key)?;
- let data = serde_json::to_string(&data)?;
-
let add_hist = AddHistoryRequest {
- id: i.id,
+ id: i.id.into(),
timestamp: i.timestamp,
data,
- hostname: hash_str(i.hostname.as_str()),
+ hostname: hash_str(&i.hostname).into(),
};
buffer.push(add_hist);
@@ -132,8 +130,8 @@ async fn sync_upload(
pub async fn sync(settings: &Settings, force: bool, db: &mut (impl Database + Send)) -> Result<()> {
let client = api_client::Client::new(
- settings.sync_address.as_str(),
- settings.session_token.as_str(),
+ &settings.sync_address,
+ &settings.session_token,
load_encoded_key(settings)?,
)?;
diff --git a/atuin-common/src/api.rs b/atuin-common/src/api.rs
index 44a73c1c..aaf8f6c5 100644
--- a/atuin-common/src/api.rs
+++ b/atuin-common/src/api.rs
@@ -1,43 +1,43 @@
-use std::convert::Infallible;
+use std::{borrow::Cow, convert::Infallible};
use chrono::Utc;
-use serde::Serialize;
+use serde::{Deserialize, Serialize};
use warp::{reply::Response, Reply};
#[derive(Debug, Serialize, Deserialize)]
-pub struct UserResponse {
- pub username: String,
+pub struct UserResponse<'a> {
+ pub username: Cow<'a, str>,
}
#[derive(Debug, Serialize, Deserialize)]
-pub struct RegisterRequest {
- pub email: String,
- pub username: String,
- pub password: String,
+pub struct RegisterRequest<'a> {
+ pub email: Cow<'a, str>,
+ pub username: Cow<'a, str>,
+ pub password: Cow<'a, str>,
}
#[derive(Debug, Serialize, Deserialize)]
-pub struct RegisterResponse {
- pub session: String,
+pub struct RegisterResponse<'a> {
+ pub session: Cow<'a, str>,
}
#[derive(Debug, Serialize, Deserialize)]
-pub struct LoginRequest {
- pub username: String,
- pub password: String,
+pub struct LoginRequest<'a> {
+ pub username: Cow<'a, str>,
+ pub password: Cow<'a, str>,
}
#[derive(Debug, Serialize, Deserialize)]
-pub struct LoginResponse {
- pub session: String,
+pub struct LoginResponse<'a> {
+ pub session: Cow<'a, str>,
}
#[derive(Debug, Serialize, Deserialize)]
-pub struct AddHistoryRequest {
- pub id: String,
+pub struct AddHistoryRequest<'a, D> {
+ pub id: Cow<'a, str>,
pub timestamp: chrono::DateTime<Utc>,
- pub data: String,
- pub hostname: String,
+ pub data: D,
+ pub hostname: Cow<'a, str>,
}
#[derive(Debug, Serialize, Deserialize)]
@@ -46,10 +46,10 @@ pub struct CountResponse {
}
#[derive(Debug, Serialize, Deserialize)]
-pub struct SyncHistoryRequest {
+pub struct SyncHistoryRequest<'a> {
pub sync_ts: chrono::DateTime<chrono::FixedOffset>,
pub history_ts: chrono::DateTime<chrono::FixedOffset>,
- pub host: String,
+ pub host: Cow<'a, str>,
}
#[derive(Debug, Serialize, Deserialize)]
@@ -58,38 +58,38 @@ pub struct SyncHistoryResponse {
}
#[derive(Debug, Serialize, Deserialize)]
-pub struct ErrorResponse {
- pub reason: String,
+pub struct ErrorResponse<'a> {
+ pub reason: Cow<'a, str>,
}
-impl Reply for ErrorResponse {
+impl Reply for ErrorResponse<'_> {
fn into_response(self) -> Response {
warp::reply::json(&self).into_response()
}
}
-pub struct ErrorResponseStatus {
- pub error: ErrorResponse,
+pub struct ErrorResponseStatus<'a> {
+ pub error: ErrorResponse<'a>,
pub status: warp::http::StatusCode,
}
-impl Reply for ErrorResponseStatus {
+impl Reply for ErrorResponseStatus<'_> {
fn into_response(self) -> Response {
warp::reply::with_status(self.error, self.status).into_response()
}
}
-impl ErrorResponse {
- pub fn with_status(self, status: warp::http::StatusCode) -> ErrorResponseStatus {
+impl<'a> ErrorResponse<'a> {
+ pub fn with_status(self, status: warp::http::StatusCode) -> ErrorResponseStatus<'a> {
ErrorResponseStatus {
error: self,
status,
}
}
- pub fn reply(reason: &str) -> ErrorResponse {
+ pub fn reply(reason: &'a str) -> ErrorResponse {
Self {
- reason: reason.to_string(),
+ reason: reason.into(),
}
}
}
diff --git a/atuin-common/src/lib.rs b/atuin-common/src/lib.rs
index 0a01e10d..e76a7abb 100644
--- a/atuin-common/src/lib.rs
+++ b/atuin-common/src/lib.rs
@@ -1,5 +1,4 @@
-#[macro_use]
-extern crate serde_derive;
+#![forbid(unsafe_code)]
pub mod api;
pub mod utils;
diff --git a/atuin-server/src/database.rs b/atuin-server/src/database.rs
index 4a3828d0..7de2a6f2 100644
--- a/atuin-server/src/database.rs
+++ b/atuin-server/src/database.rs
@@ -13,9 +13,9 @@ pub trait Database {
async fn get_session_user(&self, token: &str) -> Result<User>;
async fn add_session(&self, session: &NewSession) -> Result<()>;
- async fn get_user(&self, username: String) -> Result<User>;
+ async fn get_user(&self, username: &str) -> Result<User>;
async fn get_user_session(&self, u: &User) -> Result<Session>;
- async fn add_user(&self, user: NewUser) -> Result<i64>;
+ async fn add_user(&self, user: &NewUser) -> Result<i64>;
async fn count_history(&self, user: &User) -> Result<i64>;
async fn list_history(
@@ -23,7 +23,7 @@ pub trait Database {
user: &User,
created_since: chrono::NaiveDateTime,
since: chrono::NaiveDateTime,
- host: String,
+ host: &str,
) -> Result<Vec<History>>;
async fn add_history(&self, history: &[NewHistory]) -> Result<()>;
}
@@ -62,7 +62,7 @@ impl Database for Postgres {
}
}
- async fn get_user(&self, username: String) -> Result<User> {
+ async fn get_user(&self, username: &str) -> Result<User> {
let res: Option<User> =
sqlx::query_as::<_, User>("select * from users where username = $1")
.bind(username)
@@ -111,7 +111,7 @@ impl Database for Postgres {
user: &User,
created_since: chrono::NaiveDateTime,
since: chrono::NaiveDateTime,
- host: String,
+ host: &str,
) -> Result<Vec<History>> {
let res = sqlx::query_as::<_, History>(
"select * from history
@@ -137,6 +137,10 @@ impl Database for Postgres {
let mut tx = self.pool.begin().await?;
for i in history {
+ let client_id: &str = &i.client_id;
+ let hostname: &str = &i.hostname;
+ let data: &str = &i.data;
+
sqlx::query(
"insert into history
(client_id, user_id, hostname, timestamp, data)
@@ -144,11 +148,11 @@ impl Database for Postgres {
on conflict do nothing
",
)
- .bind(i.client_id)
+ .bind(client_id)
.bind(i.user_id)
- .bind(i.hostname)
+ .bind(hostname)
.bind(i.timestamp)
- .bind(i.data)
+ .bind(data)
.execute(&mut tx)
.await?;
}
@@ -158,16 +162,20 @@ impl Database for Postgres {
Ok(())
}
- async fn add_user(&self, user: NewUser) -> Result<i64> {
+ async fn add_user(&self, user: &NewUser) -> Result<i64> {
+ let email: &str = &user.email;
+ let username: &str = &user.username;
+ let password: &str = &user.password;
+
let res: (i64,) = sqlx::query_as(
"insert into users
(username, email, password)
values($1, $2, $3)
returning id",
)
- .bind(user.username.as_str())
- .bind(user.email.as_str())
- .bind(user.password)
+ .bind(username)
+ .bind(email)
+ .bind(password)
.fetch_one(&self.pool)
.await?;
@@ -175,13 +183,15 @@ impl Database for Postgres {
}
async fn add_session(&self, session: &NewSession) -> Result<()> {
+ let token: &str = &session.token;
+
sqlx::query(
"insert into sessions
(user_id, token)
values($1, $2)",
)
.bind(session.user_id)
- .bind(session.token)
+ .bind(token)
.execute(&self.pool)
.await?;
diff --git a/atuin-server/src/handlers/history.rs b/atuin-server/src/handlers/history.rs
index 18852b58..06715381 100644
--- a/atuin-server/src/handlers/history.rs
+++ b/atuin-server/src/handlers/history.rs
@@ -6,7 +6,7 @@ use atuin_common::api::*;
pub async fn count(
user: User,
db: impl Database + Clone + Send + Sync,
-) -> JSONResult<ErrorResponseStatus> {
+) -> JSONResult<ErrorResponseStatus<'static>> {
db.count_history(&user).await.map_or(
reply_error(
ErrorResponse::reply("failed to query history count")
@@ -17,16 +17,16 @@ pub async fn count(
}
pub async fn list(
- req: SyncHistoryRequest,
+ req: SyncHistoryRequest<'_>,
user: User,
db: impl Database + Clone + Send + Sync,
-) -> JSONResult<ErrorResponseStatus> {
+) -> JSONResult<ErrorResponseStatus<'static>> {
let history = db
.list_history(
&user,
req.sync_ts.naive_utc(),
req.history_ts.naive_utc(),
- req.host,
+ &req.host,
)
.await;
@@ -54,20 +54,20 @@ pub async fn list(
}
pub async fn add(
- req: Vec<AddHistoryRequest>,
+ req: Vec<AddHistoryRequest<'_, String>>,
user: User,
db: impl Database + Clone + Send + Sync,
-) -> ReplyResult<impl Reply, ErrorResponseStatus> {
+) -> ReplyResult<impl Reply, ErrorResponseStatus<'_>> {
debug!("request to add {} history items", req.len());
let history: Vec<NewHistory> = req
- .iter()
+ .into_iter()
.map(|h| NewHistory {
- client_id: h.id.as_str(),
+ client_id: h.id,
user_id: user.id,
- hostname: h.hostname.as_str(),
+ hostname: h.hostname,
timestamp: h.timestamp.naive_utc(),
- data: h.data.as_str(),
+ data: h.data.into(),
})
.collect();
diff --git a/atuin-server/src/handlers/user.rs b/atuin-server/src/handlers/user.rs
index ed779168..8144adab 100644
--- a/atuin-server/src/handlers/user.rs
+++ b/atuin-server/src/handlers/user.rs
@@ -1,3 +1,5 @@
+use std::borrow::Borrow;
+
use atuin_common::api::*;
use atuin_common::utils::hash_secret;
use sodiumoxide::crypto::pwhash::argon2id13;
@@ -23,10 +25,10 @@ pub fn verify_str(secret: &str, verify: &str) -> bool {
}
pub async fn get(
- username: String,
+ username: impl AsRef<str>,
db: impl Database + Clone + Send + Sync,
-) -> JSONResult<ErrorResponseStatus> {
- let user = match db.get_user(username).await {