use hcaptcha_no_wasm::Hcaptcha;
use std::collections::HashMap;
use axum::{
http::StatusCode,
response::{IntoResponse, Response},
Json,
};
use serde::{Deserialize, Serialize};
use databeam::DefaultReturn;
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct Profile {
pub id: String,
pub username: String,
pub password: String,
pub salt: String,
pub tokens: Vec<String>,
pub ips: Vec<String>,
pub token_context: Vec<TokenContext>,
pub metadata: ProfileMetadata,
pub badges: Vec<(String, String, String)>,
pub group: i32,
pub joined: u128,
pub tier: i32,
pub labels: Vec<String>,
}
impl Profile {
pub fn global() -> Self {
Self {
username: "@".to_string(),
id: "@".to_string(),
password: String::new(),
salt: String::new(),
tokens: Vec::new(),
ips: Vec::new(),
token_context: Vec::new(),
group: 0,
joined: 0,
metadata: ProfileMetadata::default(),
badges: Vec::new(),
tier: 0,
labels: Vec::new(),
}
}
pub fn system() -> Self {
Self {
username: "system".to_string(),
id: "0".to_string(),
password: String::new(),
salt: String::new(),
tokens: Vec::new(),
ips: Vec::new(),
token_context: Vec::new(),
group: 0,
joined: 0,
metadata: ProfileMetadata::default(),
badges: Vec::new(),
tier: 0,
labels: Vec::new(),
}
}
pub fn anonymous(tag: String) -> Self {
Self {
username: "anonymous".to_string(),
id: tag,
password: String::new(),
salt: String::new(),
tokens: Vec::new(),
ips: Vec::new(),
token_context: Vec::new(),
group: 0,
joined: 0,
metadata: ProfileMetadata::default(),
badges: Vec::new(),
tier: 0,
labels: Vec::new(),
}
}
pub fn anonymous_tag(input: &str) -> (bool, String, String, String) {
if (input != "anonymous") && !input.starts_with("anonymous#") {
return (false, String::new(), String::new(), input.to_string());
}
let split: Vec<&str> = input.split("#").collect();
(
true,
split.get(1).unwrap_or(&"unknown").to_string(),
split.get(0).unwrap().to_string(),
input.to_string(),
)
}
pub fn clean(&mut self) -> () {
self.ips = Vec::new();
self.tokens = Vec::new();
self.token_context = Vec::new();
self.salt = String::new();
self.password = String::new();
self.metadata = ProfileMetadata::default();
}
pub fn token_context_from_token(&self, token: &str) -> TokenContext {
let token = databeam::utility::hash(token.to_string());
if let Some(pos) = self.tokens.iter().position(|t| *t == token) {
if let Some(ctx) = self.token_context.get(pos) {
return ctx.to_owned();
}
return TokenContext::default();
}
return TokenContext::default();
}
}
impl Default for Profile {
fn default() -> Self {
Self {
id: String::new(),
username: String::new(),
password: String::new(),
salt: String::new(),
tokens: Vec::new(),
ips: Vec::new(),
token_context: Vec::new(),
metadata: ProfileMetadata::default(),
badges: Vec::new(),
group: 0,
joined: databeam::utility::unix_epoch_timestamp(),
tier: 0,
labels: Vec::new(),
}
}
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct TokenContext {
#[serde(default)]
pub app: Option<String>,
#[serde(default)]
pub permissions: Option<Vec<TokenPermission>>,
#[serde(default)]
pub timestamp: u128,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
pub enum TokenPermission {
ManageAssets,
ManageProfile,
ManageAccount,
Moderator,
GenerateTokens,
SendMail,
}
impl TokenContext {
pub fn app_name(&self) -> String {
if let Some(ref name) = self.app {
return name.to_string();
}
String::new()
}
pub fn can_do(&self, permission: TokenPermission) -> bool {
if let Some(ref permissions) = self.permissions {
return permissions.contains(&permission);
}
return true;
}
}
impl Default for TokenContext {
fn default() -> Self {
Self {
app: None,
permissions: None,
timestamp: databeam::utility::unix_epoch_timestamp(),
}
}
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct ProfileMetadata {
#[serde(default)]
pub email: String,
#[serde(default)]
pub kv: HashMap<String, String>,
}
impl ProfileMetadata {
pub fn exists(&self, key: &str) -> bool {
if let Some(ref value) = self.kv.get(key) {
if value.is_empty() {
return false;
}
return true;
}
false
}
pub fn is_true(&self, key: &str) -> bool {
if !self.exists(key) {
return false;
}
self.kv.get(key).unwrap() == "true"
}
pub fn soft_get(&self, key: &str) -> String {
if !self.exists(key) {
return String::new();
}
self.kv.get(key).unwrap().to_owned()
}
pub fn check(&self) -> bool {
for field in &self.kv {
if field.0 == "sparkler:custom_css" {
if field.1.len() > 64 * 128 {
return false;
}
continue;
}
if field.1.len() > 64 * 64 {
return false;
}
}
true
}
}
impl ProfileMetadata {
pub fn from_email(email: String) -> Self {
Self {
email,
kv: HashMap::new(),
}
}
}
impl Default for ProfileMetadata {
fn default() -> Self {
Self {
email: String::new(),
kv: HashMap::new(),
}
}
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct UserFollow {
pub user: String,
pub following: String,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct Notification {
pub title: String,
pub content: String,
pub address: String,
pub timestamp: u128,
pub id: String,
pub recipient: String,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct Warning {
pub id: String,
pub content: String,
pub timestamp: u128,
pub recipient: String,
pub moderator: Box<Profile>,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct IpBan {
pub id: String,
pub ip: String,
pub reason: String,
pub moderator: Box<Profile>,
pub timestamp: u128,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub enum RelationshipStatus {
Unknown,
Blocked,
Pending,
Friends,
}
impl Default for RelationshipStatus {
fn default() -> Self {
Self::Unknown
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Relationship {
pub one: Profile,
pub two: Profile,
pub status: RelationshipStatus,
pub timestamp: u128,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct IpBlock {
pub id: String,
pub ip: String,
pub user: String,
pub context: String,
pub timestamp: u128,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
pub enum Permission {
Admin,
Manager,
Helper,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct Group {
pub name: String,
pub id: i32,
pub permissions: Vec<Permission>,
}
impl Default for Group {
fn default() -> Self {
Self {
name: "default".to_string(),
id: 0,
permissions: Vec::new(),
}
}
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
pub enum MailState {
Unread,
Read,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct Mail {
pub title: String,
pub content: String,
pub timestamp: u128,
pub id: String,
pub state: MailState,
pub author: String,
pub recipient: Vec<String>,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct UserLabel {
pub id: String,
pub name: String,
pub timestamp: u128,
pub creator: String,
}
#[derive(Serialize, Deserialize, Debug, Hcaptcha)]
pub struct ProfileCreate {
pub username: String,
pub password: String,
#[captcha]
pub token: String,
}
#[derive(Serialize, Deserialize, Debug, Hcaptcha)]
pub struct ProfileLogin {
pub username: String,
pub password: String,
#[captcha]
pub token: String,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct SetProfileMetadata {
pub metadata: ProfileMetadata,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct SetProfileBadges {
pub badges: Vec<(String, String, String)>,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct SetProfileLabels {
pub labels: Vec<String>,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct SetProfileGroup {
pub group: i32,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct SetProfileTier {
pub tier: i32,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct SetProfilePassword {
pub password: String,
pub new_password: String,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct SetProfileUsername {
pub password: String,
pub new_name: String,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct NotificationCreate {
pub title: String,
pub content: String,
pub address: String,
pub recipient: String,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct WarningCreate {
pub content: String,
pub recipient: String,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct IpBanCreate {
pub ip: String,
pub reason: String,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct IpBlockCreate {
pub ip: String,
pub context: String,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct MailCreate {
pub title: String,
pub content: String,
pub recipient: Vec<String>,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct SetMailState {
pub state: MailState,
}
#[derive(Debug)]
pub enum DatabaseError {
MustBeUnique,
OutOfScope,
NotAllowed,
ValueError,
NotFound,
TooLong,
Other,
}
impl DatabaseError {
pub fn to_string(&self) -> String {
use DatabaseError::*;
match self {
MustBeUnique => String::from("One of the given values must be unique. (MustBeUnique)"),
OutOfScope => String::from(
"Cannot generate tokens with permissions the provided token doesn't have. (OutOfScope)",
),
NotAllowed => String::from("You are not allowed to access this resource. (NotAllowed)"),
ValueError => String::from("One of the field values given is invalid. (ValueError)"),
NotFound => String::from("No asset with this ID could be found. (NotFound)"),
TooLong => String::from("Given data is too long. (TooLong)"),
_ => String::from("An unspecified error has occured"),
}
}
}
impl IntoResponse for DatabaseError {
fn into_response(self) -> Response {
use crate::model::DatabaseError::*;
match self {
NotAllowed => (
StatusCode::UNAUTHORIZED,
Json(DefaultReturn::<u16> {
success: false,
message: self.to_string(),
payload: 401,
}),
)
.into_response(),
NotFound => (
StatusCode::NOT_FOUND,
Json(DefaultReturn::<u16> {
success: false,
message: self.to_string(),
payload: 404,
}),
)
.into_response(),
_ => (
StatusCode::INTERNAL_SERVER_ERROR,
Json(DefaultReturn::<u16> {
success: false,
message: self.to_string(),
payload: 500,
}),
)
.into_response(),
}
}
}