summaryrefslogtreecommitdiffstats
path: root/atuin-client/src/api_client.rs
diff options
context:
space:
mode:
Diffstat (limited to 'atuin-client/src/api_client.rs')
-rw-r--r--atuin-client/src/api_client.rs120
1 files changed, 110 insertions, 10 deletions
diff --git a/atuin-client/src/api_client.rs b/atuin-client/src/api_client.rs
index db2802c3..a8ce7b27 100644
--- a/atuin-client/src/api_client.rs
+++ b/atuin-client/src/api_client.rs
@@ -1,15 +1,24 @@
+use std::collections::HashMap;
+
use chrono::Utc;
-use eyre::Result;
-use reqwest::header::{HeaderMap, AUTHORIZATION};
-use reqwest::Url;
+use eyre::{eyre, Result};
+use reqwest::header::{HeaderMap, AUTHORIZATION, USER_AGENT};
+use reqwest::{StatusCode, Url};
use sodiumoxide::crypto::secretbox;
-use atuin_common::api::{AddHistoryRequest, CountResponse, SyncHistoryResponse};
+use atuin_common::api::{
+ AddHistoryRequest, CountResponse, LoginResponse, RegisterResponse, SyncHistoryResponse,
+};
use atuin_common::utils::hash_str;
-use crate::encryption::decrypt;
+use crate::encryption::{decode_key, decrypt};
use crate::history::History;
+const VERSION: &str = 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,
@@ -17,14 +26,70 @@ pub struct Client<'a> {
client: reqwest::Client,
}
+pub fn register(
+ address: &str,
+ username: &str,
+ email: &str,
+ password: &str,
+) -> Result<RegisterResponse> {
+ let mut map = HashMap::new();
+ map.insert("username", username);
+ map.insert("email", email);
+ map.insert("password", password);
+
+ let url = format!("{}/user/{}", address, username);
+ let resp = reqwest::blocking::get(url)?;
+
+ if resp.status().is_success() {
+ return Err(eyre!("username already in use"));
+ }
+
+ let url = format!("{}/register", address);
+ let client = reqwest::blocking::Client::new();
+ let resp = client
+ .post(url)
+ .header(USER_AGENT, format!("atuin/{}", VERSION))
+ .json(&map)
+ .send()?;
+
+ if !resp.status().is_success() {
+ return Err(eyre!("failed to register user"));
+ }
+
+ let session = resp.json::<RegisterResponse>()?;
+ 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);
+
+ let url = format!("{}/login", address);
+ let client = reqwest::blocking::Client::new();
+
+ let resp = client
+ .post(url)
+ .header(USER_AGENT, format!("atuin/{}", VERSION))
+ .json(&map)
+ .send()?;
+
+ if resp.status() != reqwest::StatusCode::OK {
+ return Err(eyre!("invalid login details"));
+ }
+
+ let session = resp.json::<LoginResponse>()?;
+ Ok(session)
+}
+
impl<'a> Client<'a> {
- pub fn new(sync_addr: &'a str, token: &'a str, key: secretbox::Key) -> Self {
- Client {
+ pub fn new(sync_addr: &'a str, token: &'a str, key: String) -> Result<Self> {
+ Ok(Client {
sync_addr,
token,
- key,
+ key: decode_key(key)?,
client: reqwest::Client::new(),
- }
+ })
}
pub async fn count(&self) -> Result<i64> {
@@ -36,7 +101,17 @@ impl<'a> Client<'a> {
let mut headers = HeaderMap::new();
headers.insert(AUTHORIZATION, token);
- let resp = self.client.get(url).headers(headers).send().await?;
+ let resp = self
+ .client
+ .get(url)
+ .header(USER_AGENT, format!("atuin/{}", VERSION))
+ .headers(headers)
+ .send()
+ .await?;
+
+ if resp.status() != StatusCode::OK {
+ return Err(eyre!("failed to get count (are you logged in?)"));
+ }
let count = resp.json::<CountResponse>().await?;
@@ -66,6 +141,7 @@ impl<'a> Client<'a> {
.client
.get(url)
.header(AUTHORIZATION, format!("Token {}", self.token))
+ .header(USER_AGENT, format!("atuin/{}", VERSION))
.send()
.await?;
@@ -88,9 +164,33 @@ impl<'a> Client<'a> {
.post(url)
.json(history)
.header(AUTHORIZATION, format!("Token {}", self.token))
+ .header(USER_AGENT, format!("atuin/{}", VERSION))
.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)
+ }
}