From 4f922e163faa5efe3997979f931fcbe768bc19dd Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Sat, 15 Apr 2023 20:16:18 +0200 Subject: [PATCH 01/27] create schemas.rs --- src/api/mod.rs | 2 ++ src/api/schemas.rs | 1 + 2 files changed, 3 insertions(+) create mode 100644 src/api/schemas.rs diff --git a/src/api/mod.rs b/src/api/mod.rs index 0d7b94c..43b41b8 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -1,3 +1,5 @@ pub mod policies; +pub mod schemas; pub use policies::instance::limits::*; +pub use schemas::*; diff --git a/src/api/schemas.rs b/src/api/schemas.rs new file mode 100644 index 0000000..a095a9f --- /dev/null +++ b/src/api/schemas.rs @@ -0,0 +1 @@ +pub mod schemas {} \ No newline at end of file From ff60853d0b5246a2349ec7f49a7c96064939631a Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Sat, 15 Apr 2023 21:12:33 +0200 Subject: [PATCH 02/27] create RegisterSchema --- src/api/schemas.rs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/api/schemas.rs b/src/api/schemas.rs index a095a9f..16b9baa 100644 --- a/src/api/schemas.rs +++ b/src/api/schemas.rs @@ -1 +1,18 @@ -pub mod schemas {} \ No newline at end of file +pub mod schemas { + use serde::{Deserialize, Serialize}; + + #[derive(Debug, Serialize, Deserialize)] + #[serde(rename_all = "snake_case")] + pub struct RegisterSchema { + username: Option, + password: Option, + consent: Option, + email: Option, + fingerprint: Option, + invite: Option, + date_of_birth: Option, + gift_code_sku_id: Option, + captcha_key: Option, + promotional_email_opt_in: Option, + } +} From e1003ac2b62394b26537d0673a321ed089dfb9f4 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Sat, 15 Apr 2023 21:16:47 +0200 Subject: [PATCH 03/27] Update RegisterSchema, add LoginSchema --- src/api/schemas.rs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/api/schemas.rs b/src/api/schemas.rs index 16b9baa..7b21e1b 100644 --- a/src/api/schemas.rs +++ b/src/api/schemas.rs @@ -4,9 +4,9 @@ pub mod schemas { #[derive(Debug, Serialize, Deserialize)] #[serde(rename_all = "snake_case")] pub struct RegisterSchema { - username: Option, + username: String, password: Option, - consent: Option, + consent: bool, email: Option, fingerprint: Option, invite: Option, @@ -15,4 +15,15 @@ pub mod schemas { captcha_key: Option, promotional_email_opt_in: Option, } + + #[derive(Debug, Serialize, Deserialize)] + #[serde(rename_all = "snake_case")] + pub struct LoginSchema { + login: String, + password: String, + undelete: Option, + captcha_key: Option, + login_source: Option, + gift_code_sku_id: Option, + } } From db45e493ec5e540dc95df3d3b802fc2ba9525af8 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Sat, 15 Apr 2023 21:20:32 +0200 Subject: [PATCH 04/27] Add TotpSchema --- src/api/schemas.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/api/schemas.rs b/src/api/schemas.rs index 7b21e1b..08634e9 100644 --- a/src/api/schemas.rs +++ b/src/api/schemas.rs @@ -26,4 +26,13 @@ pub mod schemas { login_source: Option, gift_code_sku_id: Option, } + + #[derive(Debug, Serialize, Deserialize)] + #[serde(rename_all = "snake_case")] + pub struct TotpSchema { + code: String, + ticket: String, + gift_code_sku_id: Option, + login_source: Option, + } } From 1b9ccf31544fcac1acfdee313ad2cdda9a498498 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Sat, 15 Apr 2023 22:06:18 +0200 Subject: [PATCH 05/27] add "new" method for RegSchema with custom errors --- src/api/schemas.rs | 74 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/src/api/schemas.rs b/src/api/schemas.rs index 08634e9..bb5c08b 100644 --- a/src/api/schemas.rs +++ b/src/api/schemas.rs @@ -1,4 +1,7 @@ pub mod schemas { + use std::error::Error; + use std::fmt; + use serde::{Deserialize, Serialize}; #[derive(Debug, Serialize, Deserialize)] @@ -16,6 +19,77 @@ pub mod schemas { promotional_email_opt_in: Option, } + #[derive(Debug)] + pub struct RegisterSchemaError { + message: String, + } + + impl RegisterSchemaError { + fn new(message: String) -> Self { + RegisterSchemaError { message } + } + } + + impl fmt::Display for RegisterSchemaError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.message) + } + } + + impl std::error::Error for RegisterSchemaError {} + + impl RegisterSchema { + /** + Returns a new [`Result`]. + ## Arguments + All but "String::username" and "bool::consent" are optional. + + ## Errors + You will receive a [`RegisterSchemaError`], if: + - The username is less than 2 or more than 32 characters in length + - You supply a `password` which is less than 1 or more than 72 characters in length. + + These constraints have been defined [in the Spacebar-API](https://docs.spacebar.chat/routes/) + */ + pub fn new( + username: String, + password: Option, + consent: bool, + email: Option, + fingerprint: Option, + invite: Option, + date_of_birth: Option, + gift_code_sku_id: Option, + captcha_key: Option, + promotional_email_opt_in: Option, + ) -> Result { + if username.len() < 2 || username.len() > 32 { + return Err(RegisterSchemaError::new( + "Username must be between 2 and 32 characters".to_string(), + )); + } + if password.is_some() + && (password.as_ref().unwrap().len() < 1 || password.as_ref().unwrap().len() > 72) + { + return Err(RegisterSchemaError { + message: "Password must be between 1 and 72 characters.".to_string(), + }); + } + return Ok(RegisterSchema { + username, + password, + consent, + email, + fingerprint, + invite, + date_of_birth, + gift_code_sku_id, + captcha_key, + promotional_email_opt_in, + }); + } + } + #[derive(Debug, Serialize, Deserialize)] #[serde(rename_all = "snake_case")] pub struct LoginSchema { From 30610aacfde24bc958078b43b94201c9f1847cee Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Sun, 16 Apr 2023 12:26:12 +0200 Subject: [PATCH 06/27] add tests to confirm password validation --- src/api/schemas.rs | 57 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 54 insertions(+), 3 deletions(-) diff --git a/src/api/schemas.rs b/src/api/schemas.rs index bb5c08b..eedd39c 100644 --- a/src/api/schemas.rs +++ b/src/api/schemas.rs @@ -4,7 +4,7 @@ pub mod schemas { use serde::{Deserialize, Serialize}; - #[derive(Debug, Serialize, Deserialize)] + #[derive(Debug, Serialize, Deserialize, PartialEq, Eq)] #[serde(rename_all = "snake_case")] pub struct RegisterSchema { username: String, @@ -19,9 +19,9 @@ pub mod schemas { promotional_email_opt_in: Option, } - #[derive(Debug)] + #[derive(Debug, PartialEq, Eq)] pub struct RegisterSchemaError { - message: String, + pub message: String, } impl RegisterSchemaError { @@ -110,3 +110,54 @@ pub mod schemas { login_source: Option, } } + +#[cfg(test)] +mod schemas_tests { + use super::schemas::*; + + #[test] + fn password_too_short() { + assert_eq!( + RegisterSchema::new( + "Test".to_string(), + Some("".to_string()), + true, + None, + None, + None, + None, + None, + None, + None, + ), + Err(RegisterSchemaError { + message: "Password must be between 1 and 72 characters.".to_string() + }) + ); + } + + #[test] + fn password_too_long() { + let mut long_pw = String::new(); + for _ in 0..73 { + long_pw = long_pw + "a"; + } + assert_eq!( + RegisterSchema::new( + "Test".to_string(), + Some(long_pw), + true, + None, + None, + None, + None, + None, + None, + None, + ), + Err(RegisterSchemaError { + message: "Password must be between 1 and 72 characters.".to_string() + }) + ); + } +} From b8038f52bfb2654ebd2d93abaa922a27588bdd91 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Sun, 16 Apr 2023 12:30:30 +0200 Subject: [PATCH 07/27] write tests to check username validation --- src/api/schemas.rs | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/src/api/schemas.rs b/src/api/schemas.rs index eedd39c..6eaf96e 100644 --- a/src/api/schemas.rs +++ b/src/api/schemas.rs @@ -160,4 +160,39 @@ mod schemas_tests { }) ); } + + #[test] + fn username_too_short() { + assert_eq!( + RegisterSchema::new( + "T".to_string(), + None, + true, + None, + None, + None, + None, + None, + None, + None, + ), + Err(RegisterSchemaError { + message: "Username must be between 2 and 32 characters".to_string() + }) + ); + } + + #[test] + fn username_too_long() { + let mut long_un = String::new(); + for _ in 0..33 { + long_un = long_un + "a"; + } + assert_eq!( + RegisterSchema::new(long_un, None, true, None, None, None, None, None, None, None,), + Err(RegisterSchemaError { + message: "Username must be between 2 and 32 characters".to_string() + }) + ); + } } From 98551dc2a22b98f9b4295f26f4a6c2f0a7ab1895 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Sun, 16 Apr 2023 12:32:49 +0200 Subject: [PATCH 08/27] Write test to check consent validation --- src/api/schemas.rs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/api/schemas.rs b/src/api/schemas.rs index 6eaf96e..8288ce1 100644 --- a/src/api/schemas.rs +++ b/src/api/schemas.rs @@ -75,6 +75,11 @@ pub mod schemas { message: "Password must be between 1 and 72 characters.".to_string(), }); } + if !consent { + return Err(RegisterSchemaError { + message: "Consent must be 'true' to register.".to_string(), + }); + } return Ok(RegisterSchema { username, password, @@ -195,4 +200,26 @@ mod schemas_tests { }) ); } + + #[test] + fn consent_false() { + assert_eq!( + RegisterSchema::new( + "Test".to_string(), + None, + false, + None, + None, + None, + None, + None, + None, + None, + ), + Err(RegisterSchemaError { + message: "Consent must be 'true' to register.".to_string() + }) + ); + } + } From 0ec8e3371bd8918d6c8f5abd2c9d052975b5af62 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Sun, 16 Apr 2023 12:33:57 +0200 Subject: [PATCH 09/27] add comment --- src/api/schemas.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/api/schemas.rs b/src/api/schemas.rs index 8288ce1..5a27a46 100644 --- a/src/api/schemas.rs +++ b/src/api/schemas.rs @@ -116,6 +116,8 @@ pub mod schemas { } } +// I know that some of these tests are... really really basic and unneccessary, but sometimes, I +// just feel like writing tests, so there you go :) -@bitfl0wer #[cfg(test)] mod schemas_tests { use super::schemas::*; @@ -221,5 +223,4 @@ mod schemas_tests { }) ); } - } From f4b500eadb17bd176fa2c2c8c5bc6e1884b0720a Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Sun, 16 Apr 2023 13:41:26 +0200 Subject: [PATCH 10/27] Implement LoginSchema --- src/api/schemas.rs | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/api/schemas.rs b/src/api/schemas.rs index 5a27a46..d53cd76 100644 --- a/src/api/schemas.rs +++ b/src/api/schemas.rs @@ -95,7 +95,7 @@ pub mod schemas { } } - #[derive(Debug, Serialize, Deserialize)] + #[derive(Debug, Serialize, Deserialize, PartialEq, Eq)] #[serde(rename_all = "snake_case")] pub struct LoginSchema { login: String, @@ -106,6 +106,26 @@ pub mod schemas { gift_code_sku_id: Option, } + impl LoginSchema { + pub fn new( + login: String, + password: String, + undelete: Option, + captcha_key: Option, + login_source: Option, + gift_code_sku_id: Option, + ) -> LoginSchema { + LoginSchema { + login, + password, + undelete, + captcha_key, + login_source, + gift_code_sku_id, + } + } + } + #[derive(Debug, Serialize, Deserialize)] #[serde(rename_all = "snake_case")] pub struct TotpSchema { From 6cba2f93e169a178e625b4df30f29e1763157942 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Sun, 16 Apr 2023 14:09:23 +0200 Subject: [PATCH 11/27] Added email regex validation and tests --- Cargo.toml | 3 ++- src/api/schemas.rs | 53 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index b1fe797..3f35601 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,4 +12,5 @@ serde = {version = "1.0.159", features = ["derive"]} serde_json = "1.0.95" reqwest = "0.11.16" url = "2.3.1" -chrono = "0.4.24" \ No newline at end of file +chrono = "0.4.24" +regex = "1.7.3" \ No newline at end of file diff --git a/src/api/schemas.rs b/src/api/schemas.rs index d53cd76..cddf2fb 100644 --- a/src/api/schemas.rs +++ b/src/api/schemas.rs @@ -2,6 +2,7 @@ pub mod schemas { use std::error::Error; use std::fmt; + use regex::Regex; use serde::{Deserialize, Serialize}; #[derive(Debug, Serialize, Deserialize, PartialEq, Eq)] @@ -80,6 +81,15 @@ pub mod schemas { message: "Consent must be 'true' to register.".to_string(), }); } + + let regex = + regex::Regex::new(r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$").unwrap(); + if email.clone().is_some() && !regex.is_match(email.clone().unwrap().as_str()) { + return Err(RegisterSchemaError { + message: "The provided email address is in an invalid format.".to_string(), + }); + } + return Ok(RegisterSchema { username, password, @@ -243,4 +253,47 @@ mod schemas_tests { }) ); } + + #[test] + fn invalid_email() { + assert_eq!( + RegisterSchema::new( + "Test".to_string(), + None, + true, + Some("p@p.p".to_string()), + None, + None, + None, + None, + None, + None, + ), + Err(RegisterSchemaError { + message: "The provided email address is in an invalid format.".to_string() + }) + ) + } + + #[test] + fn valid_email() { + let reg = RegisterSchema::new( + "Test".to_string(), + None, + true, + Some("me@mail.xy".to_string()), + None, + None, + None, + None, + None, + None, + ); + assert_ne!( + reg, + Err(RegisterSchemaError { + message: "The provided email address is in an invalid format.".to_string() + }) + ); + } } From fc397672f59fa90edab917f86e96b9e4eec62c19 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Sun, 16 Apr 2023 14:55:13 +0200 Subject: [PATCH 12/27] reformat file --- src/api/schemas.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/api/schemas.rs b/src/api/schemas.rs index cddf2fb..c53f183 100644 --- a/src/api/schemas.rs +++ b/src/api/schemas.rs @@ -1,5 +1,4 @@ pub mod schemas { - use std::error::Error; use std::fmt; use regex::Regex; @@ -82,8 +81,7 @@ pub mod schemas { }); } - let regex = - regex::Regex::new(r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$").unwrap(); + let regex = Regex::new(r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$").unwrap(); if email.clone().is_some() && !regex.is_match(email.clone().unwrap().as_str()) { return Err(RegisterSchemaError { message: "The provided email address is in an invalid format.".to_string(), From 7dc25dd4c68a7bbfd7224656299f29c77cd895ca Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Sun, 16 Apr 2023 15:07:15 +0200 Subject: [PATCH 13/27] add auth module --- src/api/auth/login.rs | 1 + src/api/auth/mod.rs | 5 +++++ src/api/auth/register.rs | 1 + src/api/mod.rs | 1 + src/api/policies/instance/mod.rs | 2 -- 5 files changed, 8 insertions(+), 2 deletions(-) create mode 100644 src/api/auth/login.rs create mode 100644 src/api/auth/mod.rs create mode 100644 src/api/auth/register.rs diff --git a/src/api/auth/login.rs b/src/api/auth/login.rs new file mode 100644 index 0000000..ee8788e --- /dev/null +++ b/src/api/auth/login.rs @@ -0,0 +1 @@ +pub mod login {} diff --git a/src/api/auth/mod.rs b/src/api/auth/mod.rs new file mode 100644 index 0000000..3093e74 --- /dev/null +++ b/src/api/auth/mod.rs @@ -0,0 +1,5 @@ +pub mod login; +pub mod register; + +pub use login::*; +pub use register::*; diff --git a/src/api/auth/register.rs b/src/api/auth/register.rs new file mode 100644 index 0000000..b2b72cc --- /dev/null +++ b/src/api/auth/register.rs @@ -0,0 +1 @@ +pub mod register {} diff --git a/src/api/mod.rs b/src/api/mod.rs index 43b41b8..c9d99c6 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -1,3 +1,4 @@ +pub mod auth; pub mod policies; pub mod schemas; diff --git a/src/api/policies/instance/mod.rs b/src/api/policies/instance/mod.rs index e695695..68f9d4c 100644 --- a/src/api/policies/instance/mod.rs +++ b/src/api/policies/instance/mod.rs @@ -1,5 +1,3 @@ -// src/api/policies/instance/mod.rs - pub mod limits; pub use limits::*; From f6fce684c1568851ad1fde14a3f70919c0ed7fef Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Sun, 16 Apr 2023 22:16:22 +0200 Subject: [PATCH 14/27] Rename client to instance --- src/client.rs | 10 ---------- src/instance.rs | 14 ++++++++++++++ 2 files changed, 14 insertions(+), 10 deletions(-) delete mode 100644 src/client.rs create mode 100644 src/instance.rs diff --git a/src/client.rs b/src/client.rs deleted file mode 100644 index 2033808..0000000 --- a/src/client.rs +++ /dev/null @@ -1,10 +0,0 @@ -use crate::gateway::Gateway; -use crate::limit::LimitedRequester; - -struct ClientBuilder {} - -/* impl ClientBuilder { - fn build() -> Client {} -} */ - -struct Client {} diff --git a/src/instance.rs b/src/instance.rs new file mode 100644 index 0000000..b2f6f91 --- /dev/null +++ b/src/instance.rs @@ -0,0 +1,14 @@ +use crate::api::schemas::schemas::InstancePoliciesSchema; +use crate::gateway::Gateway; +use crate::limit::LimitedRequester; +use crate::URLBundle; + +use std::collections::HashMap; + +#[derive(Debug)] +pub struct Instance { + main_url: String, + urls: URLBundle, + instance_info: InstancePoliciesSchema, + requester: LimitedRequester, +} From 4c9ddc456929c0c24263eb0c18070c56b2cdab70 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Sun, 16 Apr 2023 22:16:39 +0200 Subject: [PATCH 15/27] Add PartialEq and Eq derives --- src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index ee1ae54..838f31b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,11 +1,11 @@ mod api; -mod client; mod gateway; +mod instance; mod limit; mod voice; use url::{ParseError, Url}; -#[derive(Clone, Default, Debug)] +#[derive(Clone, Default, Debug, PartialEq, Eq)] /// A URLBundle is a struct which bundles together the API-, Gateway- and CDN-URLs of a Spacebar /// instance. From fde38bc3581330cfb5a278385a8577c0f9b4e03d Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Sun, 16 Apr 2023 22:18:51 +0200 Subject: [PATCH 16/27] remove impl LoginSchema, add InstancePolicies --- src/api/schemas.rs | 33 +++++++++++++-------------------- 1 file changed, 13 insertions(+), 20 deletions(-) diff --git a/src/api/schemas.rs b/src/api/schemas.rs index c53f183..5e86a33 100644 --- a/src/api/schemas.rs +++ b/src/api/schemas.rs @@ -114,26 +114,6 @@ pub mod schemas { gift_code_sku_id: Option, } - impl LoginSchema { - pub fn new( - login: String, - password: String, - undelete: Option, - captcha_key: Option, - login_source: Option, - gift_code_sku_id: Option, - ) -> LoginSchema { - LoginSchema { - login, - password, - undelete, - captcha_key, - login_source, - gift_code_sku_id, - } - } - } - #[derive(Debug, Serialize, Deserialize)] #[serde(rename_all = "snake_case")] pub struct TotpSchema { @@ -142,6 +122,19 @@ pub mod schemas { gift_code_sku_id: Option, login_source: Option, } + + #[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] + #[serde(rename_all = "camelCase")] + pub struct InstancePoliciesSchema { + instance_name: String, + instance_description: Option, + front_page: Option, + tos_page: Option, + correspondence_email: Option, + correspondence_user_ID: Option, + image: Option, + instance_ID: Option, + } } // I know that some of these tests are... really really basic and unneccessary, but sometimes, I From 1319ca173697d6535432e7a6f7b0f8fb3f0908e6 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Sun, 16 Apr 2023 22:50:51 +0200 Subject: [PATCH 17/27] use camel case --- src/api/schemas.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/api/schemas.rs b/src/api/schemas.rs index 5e86a33..df44cfc 100644 --- a/src/api/schemas.rs +++ b/src/api/schemas.rs @@ -131,9 +131,9 @@ pub mod schemas { front_page: Option, tos_page: Option, correspondence_email: Option, - correspondence_user_ID: Option, + correspondence_user_id: Option, image: Option, - instance_ID: Option, + instance_id: Option, } } From 3be962146b5891c029f23928b1e102fc3553bc98 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Sun, 16 Apr 2023 23:03:12 +0200 Subject: [PATCH 18/27] add gateway object --- src/instance.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/instance.rs b/src/instance.rs index b2f6f91..238b778 100644 --- a/src/instance.rs +++ b/src/instance.rs @@ -6,9 +6,17 @@ use crate::URLBundle; use std::collections::HashMap; #[derive(Debug)] +/** +The [`Instance`] what you will be using to perform all sorts of actions on the Spacebar server. + */ pub struct Instance { main_url: String, urls: URLBundle, instance_info: InstancePoliciesSchema, requester: LimitedRequester, + gateway: Gateway, +} + +impl Instance { + pub fn new() {} } From dc5cd09091fc78bc7e429858c770b872027556d3 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Sun, 16 Apr 2023 23:03:24 +0200 Subject: [PATCH 19/27] start working on register --- src/api/auth/register.rs | 8 +++++++- src/gateway.rs | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/api/auth/register.rs b/src/api/auth/register.rs index b2b72cc..f515703 100644 --- a/src/api/auth/register.rs +++ b/src/api/auth/register.rs @@ -1 +1,7 @@ -pub mod register {} +pub mod register { + use crate::instance::Instance; + + impl Instance { + pub fn register() {} + } +} diff --git a/src/gateway.rs b/src/gateway.rs index 5489064..e4ba3c9 100644 --- a/src/gateway.rs +++ b/src/gateway.rs @@ -1 +1,2 @@ +#[derive(Debug)] pub struct Gateway {} From f12d5ed8f6c9c34cdf02abfd13a61a3bd34d4402 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Mon, 17 Apr 2023 21:31:15 +0200 Subject: [PATCH 20/27] add Token struct and impl --- src/instance.rs | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/src/instance.rs b/src/instance.rs index 238b778..8ede575 100644 --- a/src/instance.rs +++ b/src/instance.rs @@ -1,9 +1,12 @@ +use regex::Regex; + use crate::api::schemas::schemas::InstancePoliciesSchema; use crate::gateway::Gateway; use crate::limit::LimitedRequester; use crate::URLBundle; use std::collections::HashMap; +use std::fmt; #[derive(Debug)] /** @@ -15,8 +18,46 @@ pub struct Instance { instance_info: InstancePoliciesSchema, requester: LimitedRequester, gateway: Gateway, + users: HashMap, } impl Instance { pub fn new() {} } + +#[derive(Debug, PartialEq, Eq)] +pub struct Token { + pub token: String, +} + +impl Token { + pub fn new(token: String) -> Result { + let token_regex = Regex::new(r"/[\w-]{24}\.[\w-]{6}\.[\w-]{27}/").unwrap(); + let mfa_token_regex = Regex::new(r"/mfa\.[\w-]{84}/").unwrap(); + if !token_regex.is_match(&token.as_str()) && !mfa_token_regex.is_match(&token.as_str()) { + return Err(TokenFormatError { + message: "This does not seem to be a valid token.".to_string(), + }); + } + Ok(Token { token }) + } +} + +#[derive(Debug, PartialEq, Eq)] +pub struct TokenFormatError { + pub message: String, +} + +impl TokenFormatError { + fn new(message: String) -> Self { + TokenFormatError { message } + } +} + +impl fmt::Display for TokenFormatError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.message) + } +} + +impl std::error::Error for TokenFormatError {} From d4ea4bd096e0968472b02fcd7d1b7eedb9fae8b5 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Mon, 17 Apr 2023 22:38:21 +0200 Subject: [PATCH 21/27] remove token check, add username impl --- src/instance.rs | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/instance.rs b/src/instance.rs index 8ede575..ac55b6a 100644 --- a/src/instance.rs +++ b/src/instance.rs @@ -1,5 +1,3 @@ -use regex::Regex; - use crate::api::schemas::schemas::InstancePoliciesSchema; use crate::gateway::Gateway; use crate::limit::LimitedRequester; @@ -13,12 +11,11 @@ use std::fmt; The [`Instance`] what you will be using to perform all sorts of actions on the Spacebar server. */ pub struct Instance { - main_url: String, urls: URLBundle, instance_info: InstancePoliciesSchema, requester: LimitedRequester, gateway: Gateway, - users: HashMap, + users: HashMap, } impl Instance { @@ -30,34 +27,37 @@ pub struct Token { pub token: String, } -impl Token { - pub fn new(token: String) -> Result { - let token_regex = Regex::new(r"/[\w-]{24}\.[\w-]{6}\.[\w-]{27}/").unwrap(); - let mfa_token_regex = Regex::new(r"/mfa\.[\w-]{84}/").unwrap(); - if !token_regex.is_match(&token.as_str()) && !mfa_token_regex.is_match(&token.as_str()) { - return Err(TokenFormatError { - message: "This does not seem to be a valid token.".to_string(), - }); +#[derive(Debug, PartialEq, Eq)] +pub struct Username { + pub username: String, +} + +impl Username { + pub fn new(username: String) -> Result { + if username.len() < 2 || username.len() > 32 { + return Err(UsernameFormatError::new( + "Username must be between 2 and 32 characters".to_string(), + )); } - Ok(Token { token }) + return Ok(Username { username }); } } #[derive(Debug, PartialEq, Eq)] -pub struct TokenFormatError { +pub struct UsernameFormatError { pub message: String, } -impl TokenFormatError { +impl UsernameFormatError { fn new(message: String) -> Self { - TokenFormatError { message } + UsernameFormatError { message } } } -impl fmt::Display for TokenFormatError { +impl fmt::Display for UsernameFormatError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.message) } } -impl std::error::Error for TokenFormatError {} +impl std::error::Error for UsernameFormatError {} From c5b9e0efee3b90f7897a3cffc814f6d84c3c2511 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Wed, 19 Apr 2023 20:41:15 +0200 Subject: [PATCH 22/27] implement getting InstancePoliciesSchema Co-authored-by: sky --- src/api/policies/instance/instance.rs | 81 +++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 src/api/policies/instance/instance.rs diff --git a/src/api/policies/instance/instance.rs b/src/api/policies/instance/instance.rs new file mode 100644 index 0000000..e509486 --- /dev/null +++ b/src/api/policies/instance/instance.rs @@ -0,0 +1,81 @@ +pub mod instance { + use std::fmt; + + use reqwest::Client; + use serde_json::from_str; + + use crate::{api::schemas::schemas::InstancePoliciesSchema, instance::Instance}; + + #[derive(Debug, PartialEq, Eq)] + pub struct InstancePoliciesError { + pub message: String, + } + + impl InstancePoliciesError { + fn new(message: String) -> Self { + InstancePoliciesError { message } + } + } + + impl fmt::Display for InstancePoliciesError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.message) + } + } + + impl std::error::Error for InstancePoliciesError {} + impl Instance { + /// Gets the instance policies schema. + /// # Errors + /// * [`InstancePoliciesError`] - If the request fails. + pub async fn instance_policies_schema( + &self, + ) -> Result { + let client = Client::new(); + let endpoint_url = self.urls.get_api().to_string() + "/policies/instance/"; + let request = match client.get(&endpoint_url).send().await { + Ok(result) => result, + Err(e) => { + return Err(InstancePoliciesError { + message: format!( + "An error occured while trying to GET from {}: {}", + endpoint_url, e + ), + }); + } + }; + + if request.status().as_str().chars().next().unwrap() != '2' { + return Err(InstancePoliciesError { + message: format!( + "Received the following error code while requesting from the route: {}", + request.status().as_str() + ), + }); + } + + let body = request.text().await.unwrap(); + let instance_policies_schema: InstancePoliciesSchema = from_str(&body).unwrap(); + Ok(instance_policies_schema) + } + } +} + +#[cfg(test)] +mod instance_policies_schema_test { + use crate::{instance::Instance, limit::LimitedRequester, URLBundle}; + + #[tokio::test] + async fn generate_instance_policies_schema() { + let urls = URLBundle::new( + "http://localhost:3001/api".to_string(), + "http://localhost:3001".to_string(), + "http://localhost:3001".to_string(), + ); + let limited_requester = LimitedRequester::new(urls.get_api().to_string()).await; + let test_instance = Instance::new(urls.clone(), limited_requester).unwrap(); + + let schema = test_instance.instance_policies_schema().await.unwrap(); + println!("{}", schema); + } +} From 6a8260c4bb7da2e19a223fcd5ed6d48f0a449289 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Wed, 19 Apr 2023 20:41:33 +0200 Subject: [PATCH 23/27] make progress on instance object creation --- src/instance.rs | 71 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 65 insertions(+), 6 deletions(-) diff --git a/src/instance.rs b/src/instance.rs index ac55b6a..f76edf8 100644 --- a/src/instance.rs +++ b/src/instance.rs @@ -1,3 +1,6 @@ +use regex::internal::Inst; + +use crate::api::instance; use crate::api::schemas::schemas::InstancePoliciesSchema; use crate::gateway::Gateway; use crate::limit::LimitedRequester; @@ -11,17 +14,68 @@ use std::fmt; The [`Instance`] what you will be using to perform all sorts of actions on the Spacebar server. */ pub struct Instance { - urls: URLBundle, - instance_info: InstancePoliciesSchema, - requester: LimitedRequester, - gateway: Gateway, - users: HashMap, + pub urls: URLBundle, + pub instance_info: InstancePoliciesSchema, + pub requester: LimitedRequester, + //pub gateway: Gateway, + //pub users: HashMap, } impl Instance { - pub fn new() {} + /// Creates a new [`Instance`]. + /// # Arguments + /// * `urls` - The [`URLBundle`] that contains all the URLs that are needed to connect to the Spacebar server. + /// * `requester` - The [`LimitedRequester`] that will be used to make requests to the Spacebar server. + /// # Errors + /// * [`InstanceError`] - If the instance cannot be created. + pub async fn new( + urls: URLBundle, + requester: LimitedRequester, + ) -> Result { + let mut instance = Instance { + urls, + instance_info: InstancePoliciesSchema::new( + // This is okay, because the instance_info will be overwritten by the instance_policies_schema() function. + "".to_string(), + None, + None, + None, + None, + None, + None, + None, + ), + requester, + //gateway: (), + //users: (), + }; + instance.instance_info = match instance.instance_policies_schema().await { + Ok(schema) => schema, + Err(e) => return Err(InstanceError{message: format!("Something seems to be wrong with the instance. Cannot get information about the instance: {}", e)}), + }; + Ok(instance) + } } +#[derive(Debug, PartialEq, Eq)] +pub struct InstanceError { + pub message: String, +} + +impl InstanceError { + fn new(message: String) -> Self { + InstanceError { message } + } +} + +impl fmt::Display for InstanceError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.message) + } +} + +impl std::error::Error for InstanceError {} + #[derive(Debug, PartialEq, Eq)] pub struct Token { pub token: String, @@ -33,6 +87,11 @@ pub struct Username { } impl Username { + /// Creates a new [`Username`]. + /// # Arguments + /// * `username` - The username that will be used to create the [`Username`]. + /// # Errors + /// * [`UsernameFormatError`] - If the username is not between 2 and 32 characters. pub fn new(username: String) -> Result { if username.len() < 2 || username.len() > 32 { return Err(UsernameFormatError::new( From d6bd7c471038ed22d1f688c689a4a041cad91a8b Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Wed, 19 Apr 2023 20:41:52 +0200 Subject: [PATCH 24/27] Include new file --- src/api/mod.rs | 1 + src/api/policies/instance/mod.rs | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/api/mod.rs b/src/api/mod.rs index c9d99c6..f619259 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -2,5 +2,6 @@ pub mod auth; pub mod policies; pub mod schemas; +pub use policies::instance::instance::*; pub use policies::instance::limits::*; pub use schemas::*; diff --git a/src/api/policies/instance/mod.rs b/src/api/policies/instance/mod.rs index 68f9d4c..b05078e 100644 --- a/src/api/policies/instance/mod.rs +++ b/src/api/policies/instance/mod.rs @@ -1,3 +1,5 @@ +pub mod instance; pub mod limits; +pub use instance::*; pub use limits::*; From db177fdaad5063793c7cbd4cfe73029b0a624e45 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Wed, 19 Apr 2023 20:42:11 +0200 Subject: [PATCH 25/27] create new() method --- src/api/schemas.rs | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/src/api/schemas.rs b/src/api/schemas.rs index df44cfc..1ca238e 100644 --- a/src/api/schemas.rs +++ b/src/api/schemas.rs @@ -135,6 +135,47 @@ pub mod schemas { image: Option, instance_id: Option, } + + impl InstancePoliciesSchema { + pub fn new( + instance_name: String, + instance_description: Option, + front_page: Option, + tos_page: Option, + correspondence_email: Option, + correspondence_user_id: Option, + image: Option, + instance_id: Option, + ) -> Self { + InstancePoliciesSchema { + instance_name, + instance_description, + front_page, + tos_page, + correspondence_email, + correspondence_user_id, + image, + instance_id, + } + } + } + + impl fmt::Display for InstancePoliciesSchema { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "InstancePoliciesSchema {{ instance_name: {}, instance_description: {}, front_page: {}, tos_page: {}, correspondence_email: {}, correspondence_user_id: {}, image: {}, instance_id: {} }}", + self.instance_name, + self.instance_description.clone().unwrap_or("None".to_string()), + self.front_page.clone().unwrap_or("None".to_string()), + self.tos_page.clone().unwrap_or("None".to_string()), + self.correspondence_email.clone().unwrap_or("None".to_string()), + self.correspondence_user_id.clone().unwrap_or("None".to_string()), + self.image.clone().unwrap_or("None".to_string()), + self.instance_id.clone().unwrap_or("None".to_string()), + ) + } + } } // I know that some of these tests are... really really basic and unneccessary, but sometimes, I From e1d004afaea069cd698c742927d8140c24fa96bc Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Wed, 19 Apr 2023 20:42:28 +0200 Subject: [PATCH 26/27] add additional documentation and TODO --- src/api/policies/instance/limits.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/api/policies/instance/limits.rs b/src/api/policies/instance/limits.rs index c370cd0..a46a29f 100644 --- a/src/api/policies/instance/limits.rs +++ b/src/api/policies/instance/limits.rs @@ -197,6 +197,10 @@ pub mod limits { /// check_limits uses the API to get the current request limits of the instance. /// It returns a `Limits` struct containing all the limits. + /// If the rate limit is disabled, then the limit is set to `u64::MAX`. + /// # Errors + /// This function will panic if the request fails or if the response body cannot be parsed. + /// TODO: Change this to return a Result and handle the errors properly. pub async fn check_limits(api_url: String) -> HashMap { let client = Client::new(); let url_parsed = crate::URLBundle::parse_url(api_url) + "/policies/instance/limits"; From 45b13e48652490df6c0a542cd02a34de7feec9a0 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Wed, 19 Apr 2023 20:58:14 +0200 Subject: [PATCH 27/27] add await to fix test error --- src/api/policies/instance/instance.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/api/policies/instance/instance.rs b/src/api/policies/instance/instance.rs index e509486..6ed8b05 100644 --- a/src/api/policies/instance/instance.rs +++ b/src/api/policies/instance/instance.rs @@ -73,7 +73,9 @@ mod instance_policies_schema_test { "http://localhost:3001".to_string(), ); let limited_requester = LimitedRequester::new(urls.get_api().to_string()).await; - let test_instance = Instance::new(urls.clone(), limited_requester).unwrap(); + let test_instance = Instance::new(urls.clone(), limited_requester) + .await + .unwrap(); let schema = test_instance.instance_policies_schema().await.unwrap(); println!("{}", schema);