initial commit

This commit is contained in:
antifallobst 2023-11-01 19:57:36 +01:00
commit 14f1c54575
Signed by: antifallobst
GPG Key ID: 2B4F402172791BAF
6 changed files with 129 additions and 0 deletions

4
.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
.idea
/target
/Cargo.lock

13
Cargo.toml Normal file
View File

@ -0,0 +1,13 @@
[package]
name = "nerdcult-sdk"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
anyhow = "1.0.75"
thiserror = "1.0.50"
serde = { version = "1.0.190", features = ["derive"] }
serde_json = "1.0.108"
reqwest = { version = "0.11.22", features = ["json"] }

25
src/error.rs Normal file
View File

@ -0,0 +1,25 @@
use thiserror::Error;
#[derive(Debug, Error)]
pub enum AuthError {
#[error("Failed to authenticate: the API complains about a malformed request")]
BadRequest,
#[error("Failed to authenticate: unprocessable API response")]
BadResponse,
#[error("Failed to authenticate: failed to send request")]
RequestSend(reqwest::Error),
#[error("Failed to authenticate: blocked for security reasons")]
Forbidden,
#[error("Failed to authenticate: wrong password")]
WrongPassword,
#[error("Failed to authenticate: account not found")]
NotFound,
#[error("Failed to authenticate: account not verified")]
NotVerified,
}

74
src/lib.rs Normal file
View File

@ -0,0 +1,74 @@
mod error;
pub mod request;
pub mod response;
use crate::{error::AuthError, request::AccountAuthenticate};
use anyhow::Result;
use reqwest::StatusCode;
use std::fmt::Debug;
#[derive(Debug, Clone)]
pub struct Session {
base_url: String,
auth_token: Option<String>,
client: reqwest::Client,
}
impl Default for Session {
fn default() -> Self {
Self {
base_url: "https://api.nerdcult.net".to_string(),
auth_token: None,
client: reqwest::Client::new(),
}
}
}
impl Session {
pub fn with_base_url(base_url: String) -> Self {
Self {
base_url,
auth_token: None,
client: reqwest::Client::new(),
}
}
pub async fn authenticate(
&mut self,
username: String,
password: String,
) -> Result<(), AuthError> {
let url = format!("{}/account/authenticate", &self.base_url);
let body = AccountAuthenticate { username, password };
let request = self.client.post(&url).json(&body);
let response = request
.send()
.await
.map_err(|e| AuthError::RequestSend(e))?;
match response.status() {
StatusCode::OK => {
self.auth_token = Some(
response
.json::<response::AccountAuthenticateResponse>()
.await
.map_err(|_| AuthError::BadResponse)?
.token,
);
Ok(())
}
StatusCode::BAD_REQUEST => Err(AuthError::BadRequest),
StatusCode::UNAUTHORIZED => Err(AuthError::WrongPassword),
StatusCode::FORBIDDEN => Err(AuthError::Forbidden),
StatusCode::NOT_FOUND => Err(AuthError::NotFound),
StatusCode::FAILED_DEPENDENCY => Err(AuthError::NotVerified),
_ => Err(AuthError::BadResponse),
}
}
pub fn is_authenticated(&self) -> bool {
self.auth_token.is_some()
}
}

7
src/request.rs Normal file
View File

@ -0,0 +1,7 @@
use serde::Serialize;
#[derive(Debug, Serialize, Clone)]
pub struct AccountAuthenticate {
pub username: String,
pub password: String,
}

6
src/response.rs Normal file
View File

@ -0,0 +1,6 @@
use serde::Deserialize;
#[derive(Debug, Deserialize, Clone)]
pub struct AccountAuthenticateResponse {
pub token: String,
}