some changes 🤷 (#83)

* make everything a cow

* fmt + clippy
This commit is contained in:
Conrad Ludgate 2021-05-09 21:17:24 +01:00 committed by GitHub
parent e43e5ce74a
commit de2e34ac50
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 134 additions and 156 deletions

View File

@ -7,21 +7,21 @@ use reqwest::{StatusCode, Url};
use sodiumoxide::crypto::secretbox; use sodiumoxide::crypto::secretbox;
use atuin_common::api::{ use atuin_common::api::{
AddHistoryRequest, CountResponse, LoginResponse, RegisterResponse, SyncHistoryResponse, AddHistoryRequest, CountResponse, LoginRequest, LoginResponse, RegisterResponse,
SyncHistoryResponse,
}; };
use atuin_common::utils::hash_str; use atuin_common::utils::hash_str;
use crate::encryption::{decode_key, decrypt}; use crate::encryption::{decode_key, decrypt, EncryptedHistory};
use crate::history::History; 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 // TODO: remove all references to the encryption key from this
// It should be handled *elsewhere* // It should be handled *elsewhere*
pub struct Client<'a> { pub struct Client<'a> {
sync_addr: &'a str, sync_addr: &'a str,
token: &'a str,
key: secretbox::Key, key: secretbox::Key,
client: reqwest::Client, client: reqwest::Client,
} }
@ -31,7 +31,7 @@ pub fn register(
username: &str, username: &str,
email: &str, email: &str,
password: &str, password: &str,
) -> Result<RegisterResponse> { ) -> Result<RegisterResponse<'static>> {
let mut map = HashMap::new(); let mut map = HashMap::new();
map.insert("username", username); map.insert("username", username);
map.insert("email", email); map.insert("email", email);
@ -48,7 +48,7 @@ pub fn register(
let client = reqwest::blocking::Client::new(); let client = reqwest::blocking::Client::new();
let resp = client let resp = client
.post(url) .post(url)
.header(USER_AGENT, format!("atuin/{}", VERSION)) .header(USER_AGENT, APP_USER_AGENT)
.json(&map) .json(&map)
.send()?; .send()?;
@ -60,18 +60,14 @@ pub fn register(
Ok(session) Ok(session)
} }
pub fn login(address: &str, username: &str, password: &str) -> Result<LoginResponse> { pub fn login(address: &str, req: LoginRequest) -> Result<LoginResponse<'static>> {
let mut map = HashMap::new();
map.insert("username", username);
map.insert("password", password);
let url = format!("{}/login", address); let url = format!("{}/login", address);
let client = reqwest::blocking::Client::new(); let client = reqwest::blocking::Client::new();
let resp = client let resp = client
.post(url) .post(url)
.header(USER_AGENT, format!("atuin/{}", VERSION)) .header(USER_AGENT, APP_USER_AGENT)
.json(&map) .json(&req)
.send()?; .send()?;
if resp.status() != reqwest::StatusCode::OK { 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> { 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 { Ok(Client {
sync_addr, sync_addr,
token,
key: decode_key(key)?, 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> { pub async fn count(&self) -> Result<i64> {
let url = format!("{}/sync/count", self.sync_addr); let url = format!("{}/sync/count", self.sync_addr);
let url = Url::parse(url.as_str())?; let url = Url::parse(url.as_str())?;
let token = format!("Token {}", self.token);
let token = token.parse()?;
let mut headers = HeaderMap::new(); let resp = self.client.get(url).send().await?;
headers.insert(AUTHORIZATION, token);
let resp = self
.client
.get(url)
.header(USER_AGENT, format!("atuin/{}", VERSION))
.headers(headers)
.send()
.await?;
if resp.status() != StatusCode::OK { if resp.status() != StatusCode::OK {
return Err(eyre!("failed to get count (are you logged in?)")); return Err(eyre!("failed to get count (are you logged in?)"));
@ -137,13 +127,7 @@ impl<'a> Client<'a> {
host, host,
); );
let resp = self let resp = self.client.get(url).send().await?;
.client
.get(url)
.header(AUTHORIZATION, format!("Token {}", self.token))
.header(USER_AGENT, format!("atuin/{}", VERSION))
.send()
.await?;
let history = resp.json::<SyncHistoryResponse>().await?; let history = resp.json::<SyncHistoryResponse>().await?;
let history = history let history = history
@ -156,41 +140,15 @@ impl<'a> Client<'a> {
Ok(history) 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 = format!("{}/history", self.sync_addr);
let url = Url::parse(url.as_str())?; let url = Url::parse(url.as_str())?;
self.client self.client.post(url).json(history).send().await?;
.post(url)
.json(history)
.header(AUTHORIZATION, format!("Token {}", self.token))
.header(USER_AGENT, format!("atuin/{}", VERSION))
.send()
.await?;
Ok(()) 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)
}
} }

View File

@ -1,3 +1,5 @@
#![forbid(unsafe_code)]
#[macro_use] #[macro_use]
extern crate log; extern crate log;

View File

@ -99,7 +99,7 @@ async fn sync_upload(
while local_count > remote_count { while local_count > remote_count {
let last = db.before(cursor, HISTORY_PAGE_SIZE).await?; let last = db.before(cursor, HISTORY_PAGE_SIZE).await?;
let mut buffer = Vec::<AddHistoryRequest>::new(); let mut buffer = Vec::new();
if last.is_empty() { if last.is_empty() {
break; break;
@ -107,13 +107,11 @@ async fn sync_upload(
for i in last { for i in last {
let data = encrypt(&i, &key)?; let data = encrypt(&i, &key)?;
let data = serde_json::to_string(&data)?;
let add_hist = AddHistoryRequest { let add_hist = AddHistoryRequest {
id: i.id, id: i.id.into(),
timestamp: i.timestamp, timestamp: i.timestamp,
data, data,
hostname: hash_str(i.hostname.as_str()), hostname: hash_str(&i.hostname).into(),
}; };
buffer.push(add_hist); 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<()> { pub async fn sync(settings: &Settings, force: bool, db: &mut (impl Database + Send)) -> Result<()> {
let client = api_client::Client::new( let client = api_client::Client::new(
settings.sync_address.as_str(), &settings.sync_address,
settings.session_token.as_str(), &settings.session_token,
load_encoded_key(settings)?, load_encoded_key(settings)?,
)?; )?;

View File

@ -1,43 +1,43 @@
use std::convert::Infallible; use std::{borrow::Cow, convert::Infallible};
use chrono::Utc; use chrono::Utc;
use serde::Serialize; use serde::{Deserialize, Serialize};
use warp::{reply::Response, Reply}; use warp::{reply::Response, Reply};
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct UserResponse { pub struct UserResponse<'a> {
pub username: String, pub username: Cow<'a, str>,
} }
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct RegisterRequest { pub struct RegisterRequest<'a> {
pub email: String, pub email: Cow<'a, str>,
pub username: String, pub username: Cow<'a, str>,
pub password: String, pub password: Cow<'a, str>,
} }
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct RegisterResponse { pub struct RegisterResponse<'a> {
pub session: String, pub session: Cow<'a, str>,
} }
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct LoginRequest { pub struct LoginRequest<'a> {
pub username: String, pub username: Cow<'a, str>,
pub password: String, pub password: Cow<'a, str>,
} }
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct LoginResponse { pub struct LoginResponse<'a> {
pub session: String, pub session: Cow<'a, str>,
} }
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct AddHistoryRequest { pub struct AddHistoryRequest<'a, D> {
pub id: String, pub id: Cow<'a, str>,
pub timestamp: chrono::DateTime<Utc>, pub timestamp: chrono::DateTime<Utc>,
pub data: String, pub data: D,
pub hostname: String, pub hostname: Cow<'a, str>,
} }
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
@ -46,10 +46,10 @@ pub struct CountResponse {
} }
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct SyncHistoryRequest { pub struct SyncHistoryRequest<'a> {
pub sync_ts: chrono::DateTime<chrono::FixedOffset>, pub sync_ts: chrono::DateTime<chrono::FixedOffset>,
pub history_ts: chrono::DateTime<chrono::FixedOffset>, pub history_ts: chrono::DateTime<chrono::FixedOffset>,
pub host: String, pub host: Cow<'a, str>,
} }
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
@ -58,38 +58,38 @@ pub struct SyncHistoryResponse {
} }
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct ErrorResponse { pub struct ErrorResponse<'a> {
pub reason: String, pub reason: Cow<'a, str>,
} }
impl Reply for ErrorResponse { impl Reply for ErrorResponse<'_> {
fn into_response(self) -> Response { fn into_response(self) -> Response {
warp::reply::json(&self).into_response() warp::reply::json(&self).into_response()
} }
} }
pub struct ErrorResponseStatus { pub struct ErrorResponseStatus<'a> {
pub error: ErrorResponse, pub error: ErrorResponse<'a>,
pub status: warp::http::StatusCode, pub status: warp::http::StatusCode,
} }
impl Reply for ErrorResponseStatus { impl Reply for ErrorResponseStatus<'_> {
fn into_response(self) -> Response { fn into_response(self) -> Response {
warp::reply::with_status(self.error, self.status).into_response() warp::reply::with_status(self.error, self.status).into_response()
} }
} }
impl ErrorResponse { impl<'a> ErrorResponse<'a> {
pub fn with_status(self, status: warp::http::StatusCode) -> ErrorResponseStatus { pub fn with_status(self, status: warp::http::StatusCode) -> ErrorResponseStatus<'a> {
ErrorResponseStatus { ErrorResponseStatus {
error: self, error: self,
status, status,
} }
} }
pub fn reply(reason: &str) -> ErrorResponse { pub fn reply(reason: &'a str) -> ErrorResponse {
Self { Self {
reason: reason.to_string(), reason: reason.into(),
} }
} }
} }

View File

@ -1,5 +1,4 @@
#[macro_use] #![forbid(unsafe_code)]
extern crate serde_derive;
pub mod api; pub mod api;
pub mod utils; pub mod utils;

View File

@ -13,9 +13,9 @@ pub trait Database {
async fn get_session_user(&self, token: &str) -> Result<User>; async fn get_session_user(&self, token: &str) -> Result<User>;
async fn add_session(&self, session: &NewSession) -> Result<()>; 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 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 count_history(&self, user: &User) -> Result<i64>;
async fn list_history( async fn list_history(
@ -23,7 +23,7 @@ pub trait Database {
user: &User, user: &User,
created_since: chrono::NaiveDateTime, created_since: chrono::NaiveDateTime,
since: chrono::NaiveDateTime, since: chrono::NaiveDateTime,
host: String, host: &str,
) -> Result<Vec<History>>; ) -> Result<Vec<History>>;
async fn add_history(&self, history: &[NewHistory]) -> Result<()>; 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> = let res: Option<User> =
sqlx::query_as::<_, User>("select * from users where username = $1") sqlx::query_as::<_, User>("select * from users where username = $1")
.bind(username) .bind(username)
@ -111,7 +111,7 @@ impl Database for Postgres {
user: &User, user: &User,
created_since: chrono::NaiveDateTime, created_since: chrono::NaiveDateTime,
since: chrono::NaiveDateTime, since: chrono::NaiveDateTime,
host: String, host: &str,
) -> Result<Vec<History>> { ) -> Result<Vec<History>> {
let res = sqlx::query_as::<_, History>( let res = sqlx::query_as::<_, History>(
"select * from history "select * from history
@ -137,6 +137,10 @@ impl Database for Postgres {
let mut tx = self.pool.begin().await?; let mut tx = self.pool.begin().await?;
for i in history { for i in history {
let client_id: &str = &i.client_id;
let hostname: &str = &i.hostname;
let data: &str = &i.data;
sqlx::query( sqlx::query(
"insert into history "insert into history
(client_id, user_id, hostname, timestamp, data) (client_id, user_id, hostname, timestamp, data)
@ -144,11 +148,11 @@ impl Database for Postgres {
on conflict do nothing on conflict do nothing
", ",
) )
.bind(i.client_id) .bind(client_id)
.bind(i.user_id) .bind(i.user_id)
.bind(i.hostname) .bind(hostname)
.bind(i.timestamp) .bind(i.timestamp)
.bind(i.data) .bind(data)
.execute(&mut tx) .execute(&mut tx)
.await?; .await?;
} }
@ -158,16 +162,20 @@ impl Database for Postgres {
Ok(()) 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( let res: (i64,) = sqlx::query_as(
"insert into users "insert into users
(username, email, password) (username, email, password)
values($1, $2, $3) values($1, $2, $3)
returning id", returning id",
) )
.bind(user.username.as_str()) .bind(username)
.bind(user.email.as_str()) .bind(email)
.bind(user.password) .bind(password)
.fetch_one(&self.pool) .fetch_one(&self.pool)
.await?; .await?;
@ -175,13 +183,15 @@ impl Database for Postgres {
} }
async fn add_session(&self, session: &NewSession) -> Result<()> { async fn add_session(&self, session: &NewSession) -> Result<()> {
let token: &str = &session.token;
sqlx::query( sqlx::query(
"insert into sessions "insert into sessions
(user_id, token) (user_id, token)
values($1, $2)", values($1, $2)",
) )
.bind(session.user_id) .bind(session.user_id)
.bind(session.token) .bind(token)
.execute(&self.pool) .execute(&self.pool)
.await?; .await?;

View File

@ -6,7 +6,7 @@ use atuin_common::api::*;
pub async fn count( pub async fn count(
user: User, user: User,
db: impl Database + Clone + Send + Sync, db: impl Database + Clone + Send + Sync,
) -> JSONResult<ErrorResponseStatus> { ) -> JSONResult<ErrorResponseStatus<'static>> {
db.count_history(&user).await.map_or( db.count_history(&user).await.map_or(
reply_error( reply_error(
ErrorResponse::reply("failed to query history count") ErrorResponse::reply("failed to query history count")
@ -17,16 +17,16 @@ pub async fn count(
} }
pub async fn list( pub async fn list(
req: SyncHistoryRequest, req: SyncHistoryRequest<'_>,
user: User, user: User,
db: impl Database + Clone + Send + Sync, db: impl Database + Clone + Send + Sync,
) -> JSONResult<ErrorResponseStatus> { ) -> JSONResult<ErrorResponseStatus<'static>> {
let history = db let history = db
.list_history( .list_history(
&user, &user,
req.sync_ts.naive_utc(), req.sync_ts.naive_utc(),
req.history_ts.naive_utc(), req.history_ts.naive_utc(),
req.host, &req.host,
) )
.await; .await;
@ -54,20 +54,20 @@ pub async fn list(
} }
pub async fn add( pub async fn add(
req: Vec<AddHistoryRequest>, req: Vec<AddHistoryRequest<'_, String>>,
user: User, user: User,
db: impl Database + Clone + Send + Sync, db: impl Database + Clone + Send + Sync,
) -> ReplyResult<impl Reply, ErrorResponseStatus> { ) -> ReplyResult<impl Reply, ErrorResponseStatus<'_>> {
debug!("request to add {} history items", req.len()); debug!("request to add {} history items", req.len());
let history: Vec<NewHistory> = req let history: Vec<NewHistory> = req
.iter() .into_iter()
.map(|h| NewHistory { .map(|h| NewHistory {
client_id: h.id.as_str(), client_id: h.id,
user_id: user.id, user_id: user.id,
hostname: h.hostname.as_str(), hostname: h.hostname,
timestamp: h.timestamp.naive_utc(), timestamp: h.timestamp.naive_utc(),
data: h.data.as_str(), data: h.data.into(),
}) })
.collect(); .collect();

View File

@ -1,3 +1,5 @@
use std::borrow::Borrow;
use atuin_common::api::*; use atuin_common::api::*;
use atuin_common::utils::hash_secret; use atuin_common::utils::hash_secret;
use sodiumoxide::crypto::pwhash::argon2id13; use sodiumoxide::crypto::pwhash::argon2id13;
@ -23,10 +25,10 @@ pub fn verify_str(secret: &str, verify: &str) -> bool {
} }
pub async fn get( pub async fn get(
username: String, username: impl AsRef<str>,
db: impl Database + Clone + Send + Sync, db: impl Database + Clone + Send + Sync,
) -> JSONResult<ErrorResponseStatus> { ) -> JSONResult<ErrorResponseStatus<'static>> {
let user = match db.get_user(username).await { let user = match db.get_user(username.as_ref()).await {
Ok(user) => user, Ok(user) => user,
Err(e) => { Err(e) => {
debug!("user not found: {}", e); debug!("user not found: {}", e);
@ -37,15 +39,15 @@ pub async fn get(
}; };
reply_json(UserResponse { reply_json(UserResponse {
username: user.username, username: user.username.into(),
}) })
} }
pub async fn register( pub async fn register(
register: RegisterRequest, register: RegisterRequest<'_>,
settings: Settings, settings: Settings,
db: impl Database + Clone + Send + Sync, db: impl Database + Clone + Send + Sync,
) -> JSONResult<ErrorResponseStatus> { ) -> JSONResult<ErrorResponseStatus<'static>> {
if !settings.open_registration { if !settings.open_registration {
return reply_error( return reply_error(
ErrorResponse::reply("this server is not open for registrations") ErrorResponse::reply("this server is not open for registrations")
@ -53,15 +55,15 @@ pub async fn register(
); );
} }
let hashed = hash_secret(register.password.as_str()); let hashed = hash_secret(&register.password);
let new_user = NewUser { let new_user = NewUser {
email: register.email, email: register.email,
username: register.username, username: register.username,
password: hashed, password: hashed.into(),
}; };
let user_id = match db.add_user(new_user).await { let user_id = match db.add_user(&new_user).await {
Ok(id) => id, Ok(id) => id,
Err(e) => { Err(e) => {
error!("failed to add user: {}", e); error!("failed to add user: {}", e);
@ -75,11 +77,13 @@ pub async fn register(
let new_session = NewSession { let new_session = NewSession {
user_id, user_id,
token: token.as_str(), token: (&token).into(),
}; };
match db.add_session(&new_session).await { match db.add_session(&new_session).await {
Ok(_) => reply_json(RegisterResponse { session: token }), Ok(_) => reply_json(RegisterResponse {
session: token.into(),
}),
Err(e) => { Err(e) => {
error!("failed to add session: {}", e); error!("failed to add session: {}", e);
reply_error( reply_error(
@ -91,10 +95,10 @@ pub async fn register(
} }
pub async fn login( pub async fn login(
login: LoginRequest, login: LoginRequest<'_>,
db: impl Database + Clone + Send + Sync, db: impl Database + Clone + Send + Sync,
) -> JSONResult<ErrorResponseStatus> { ) -> JSONResult<ErrorResponseStatus<'_>> {
let user = match db.get_user(login.username.clone()).await { let user = match db.get_user(login.username.borrow()).await {
Ok(u) => u, Ok(u) => u,
Err(e) => { Err(e) => {
error!("failed to get user {}: {}", login.username.clone(), e); error!("failed to get user {}: {}", login.username.clone(), e);
@ -116,7 +120,7 @@ pub async fn login(
} }
}; };
let verified = verify_str(user.password.as_str(), login.password.as_str()); let verified = verify_str(user.password.as_str(), login.password.borrow());
if !verified { if !verified {
return reply_error( return reply_error(
@ -125,6 +129,6 @@ pub async fn login(
} }
reply_json(LoginResponse { reply_json(LoginResponse {
session: session.token, session: session.token.into(),
}) })
} }

View File

@ -1,3 +1,5 @@
#![forbid(unsafe_code)]
use std::net::IpAddr; use std::net::IpAddr;
use eyre::Result; use eyre::Result;

View File

@ -1,3 +1,5 @@
use std::borrow::Cow;
use chrono::prelude::*; use chrono::prelude::*;
#[derive(sqlx::FromRow)] #[derive(sqlx::FromRow)]
@ -14,12 +16,12 @@ pub struct History {
} }
pub struct NewHistory<'a> { pub struct NewHistory<'a> {
pub client_id: &'a str, pub client_id: Cow<'a, str>,
pub user_id: i64, pub user_id: i64,
pub hostname: &'a str, pub hostname: Cow<'a, str>,
pub timestamp: chrono::NaiveDateTime, pub timestamp: chrono::NaiveDateTime,
pub data: &'a str, pub data: Cow<'a, str>,
} }
#[derive(sqlx::FromRow)] #[derive(sqlx::FromRow)]
@ -37,13 +39,13 @@ pub struct Session {
pub token: String, pub token: String,
} }
pub struct NewUser { pub struct NewUser<'a> {
pub username: String, pub username: Cow<'a, str>,
pub email: String, pub email: Cow<'a, str>,
pub password: String, pub password: Cow<'a, str>,
} }
pub struct NewSession<'a> { pub struct NewSession<'a> {
pub user_id: i64, pub user_id: i64,
pub token: &'a str, pub token: Cow<'a, str>,
} }

View File

@ -1,6 +1,7 @@
use std::fs::File;
use std::io::prelude::*; use std::io::prelude::*;
use std::{borrow::Cow, fs::File};
use atuin_common::api::LoginRequest;
use eyre::Result; use eyre::Result;
use structopt::StructOpt; use structopt::StructOpt;
@ -34,8 +35,10 @@ impl Cmd {
let session = api_client::login( let session = api_client::login(
settings.sync_address.as_str(), settings.sync_address.as_str(),
self.username.as_str(), LoginRequest {
self.password.as_str(), username: Cow::Borrowed(&self.username),
password: Cow::Borrowed(&self.password),
},
)?; )?;
let session_path = settings.session_path.as_str(); let session_path = settings.session_path.as_str();