forked from jmug/stoatchat
New perm concept, reference, and adding routes.
This commit is contained in:
7
Cargo.lock
generated
7
Cargo.lock
generated
@@ -1203,6 +1203,12 @@ version = "1.0.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1f7280c75fb2e2fc47080ec80ccc481376923acb04501957fc38f935c3de5088"
|
checksum = "1f7280c75fb2e2fc47080ec80ccc481376923acb04501957fc38f935c3de5088"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "impl_ops"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "90f97a5f38dd3ccfbe7aa80f4a0c00930f21b922c74195be0201c51028f22dcf"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indexmap"
|
name = "indexmap"
|
||||||
version = "1.6.1"
|
version = "1.6.1"
|
||||||
@@ -2346,6 +2352,7 @@ dependencies = [
|
|||||||
"env_logger",
|
"env_logger",
|
||||||
"futures",
|
"futures",
|
||||||
"hive_pubsub",
|
"hive_pubsub",
|
||||||
|
"impl_ops",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"lettre",
|
"lettre",
|
||||||
"log",
|
"log",
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ edition = "2018"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
futures = "0.3.8"
|
futures = "0.3.8"
|
||||||
many-to-many = "0.1.2"
|
many-to-many = "0.1.2"
|
||||||
|
impl_ops = "0.1.1"
|
||||||
ctrlc = { version = "3.0", features = ["termination"] }
|
ctrlc = { version = "3.0", features = ["termination"] }
|
||||||
async-tungstenite = { version = "0.10.0", features = ["async-std-runtime"] }
|
async-tungstenite = { version = "0.10.0", features = ["async-std-runtime"] }
|
||||||
rauth = { git = "https://gitlab.insrt.uk/insert/rauth" }
|
rauth = { git = "https://gitlab.insrt.uk/insert/rauth" }
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
/*#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
pub struct LastMessage {
|
pub struct LastMessage {
|
||||||
id: String,
|
id: String,
|
||||||
user_id: String,
|
user_id: String,
|
||||||
@@ -28,4 +28,23 @@ pub struct Channel {
|
|||||||
pub name: Option<String>,
|
pub name: Option<String>,
|
||||||
// GUILD + GDM: channel description
|
// GUILD + GDM: channel description
|
||||||
pub description: Option<String>,
|
pub description: Option<String>,
|
||||||
|
}*/
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
#[serde(tag = "type")]
|
||||||
|
pub enum Channel {
|
||||||
|
DirectMessage {
|
||||||
|
#[serde(rename = "_id")]
|
||||||
|
id: String,
|
||||||
|
active: bool,
|
||||||
|
recipients: Vec<String>,
|
||||||
|
},
|
||||||
|
Group {
|
||||||
|
#[serde(rename = "_id")]
|
||||||
|
id: String,
|
||||||
|
name: String,
|
||||||
|
owner: String,
|
||||||
|
description: String,
|
||||||
|
recipients: Vec<String>,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
// use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
/*#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
pub struct MemberCompositeKey {
|
pub struct MemberCompositeKey {
|
||||||
pub guild: String,
|
pub guild: String,
|
||||||
pub user: String,
|
pub user: String,
|
||||||
@@ -40,4 +40,4 @@ pub struct Guild {
|
|||||||
pub bans: Vec<Ban>,
|
pub bans: Vec<Ban>,
|
||||||
|
|
||||||
pub default_permissions: u32,
|
pub default_permissions: u32,
|
||||||
}
|
}*/
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use mongodb::bson::DateTime;
|
// use mongodb::bson::DateTime;
|
||||||
use serde::{Deserialize, Serialize};
|
// use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
/*#[derive(Serialize, Deserialize, Debug)]
|
||||||
pub struct PreviousEntry {
|
pub struct PreviousEntry {
|
||||||
pub content: String,
|
pub content: String,
|
||||||
pub time: DateTime,
|
pub time: DateTime,
|
||||||
@@ -19,4 +19,4 @@ pub struct Message {
|
|||||||
pub edited: Option<DateTime>,
|
pub edited: Option<DateTime>,
|
||||||
|
|
||||||
pub previous_content: Vec<PreviousEntry>,
|
pub previous_content: Vec<PreviousEntry>,
|
||||||
}
|
}*/
|
||||||
|
|||||||
@@ -5,17 +5,18 @@ use serde::{Deserialize, Serialize};
|
|||||||
use crate::database::get_collection;
|
use crate::database::get_collection;
|
||||||
use rocket::request::{self, FromRequest, Outcome, Request};
|
use rocket::request::{self, FromRequest, Outcome, Request};
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
pub struct Relationship {
|
pub struct Relationship {
|
||||||
pub id: String,
|
pub id: String,
|
||||||
pub status: u8,
|
pub status: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
pub struct User {
|
pub struct User {
|
||||||
#[serde(rename = "_id")]
|
#[serde(rename = "_id")]
|
||||||
pub id: String,
|
pub id: String,
|
||||||
pub username: String,
|
pub username: String,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub relations: Option<Vec<Relationship>>,
|
pub relations: Option<Vec<Relationship>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,35 +44,5 @@ impl<'a, 'r> FromRequest<'a, 'r> for User {
|
|||||||
} else {
|
} else {
|
||||||
Outcome::Failure((Status::InternalServerError, rauth::util::Error::DatabaseError))
|
Outcome::Failure((Status::InternalServerError, rauth::util::Error::DatabaseError))
|
||||||
}
|
}
|
||||||
|
|
||||||
/*Outcome::Success(
|
|
||||||
User {
|
|
||||||
id: "gaming".to_string(),
|
|
||||||
username: None,
|
|
||||||
relations: None
|
|
||||||
}
|
|
||||||
)*/
|
|
||||||
|
|
||||||
/*match (
|
|
||||||
request.managed_state::<Auth>(),
|
|
||||||
header_user_id,
|
|
||||||
header_session_token,
|
|
||||||
) {
|
|
||||||
(Some(auth), Some(user_id), Some(session_token)) => {
|
|
||||||
let session = Session {
|
|
||||||
id: None,
|
|
||||||
user_id,
|
|
||||||
session_token,
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Ok(session) = auth.verify_session(session).await {
|
|
||||||
Outcome::Success(session)
|
|
||||||
} else {
|
|
||||||
Outcome::Failure((Status::Forbidden, Error::InvalidSession))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
(None, _, _) => Outcome::Failure((Status::InternalServerError, Error::InternalError)),
|
|
||||||
(_, _, _) => Outcome::Failure((Status::Forbidden, Error::MissingHeaders)),
|
|
||||||
}*/
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
use mongodb::bson::{doc, from_bson, Bson};
|
||||||
|
use crate::util::result::{Error, Result};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use crate::database::get_collection;
|
||||||
|
use crate::database::entities::*;
|
||||||
|
use rocket::request::FromParam;
|
||||||
|
use rocket::http::RawStr;
|
||||||
|
use validator::Validate;
|
||||||
|
|
||||||
|
#[derive(Validate, Serialize, Deserialize)]
|
||||||
|
pub struct Ref {
|
||||||
|
#[validate(length(min = 26, max = 26))]
|
||||||
|
id: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ref {
|
||||||
|
pub fn from(id: String) -> Result<Ref> {
|
||||||
|
Ok(Ref { id })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn fetch_user(self) -> Result<User> {
|
||||||
|
let doc = get_collection("users")
|
||||||
|
.find_one(
|
||||||
|
doc! {
|
||||||
|
"_id": self.id
|
||||||
|
},
|
||||||
|
None
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map_err(|_| Error::DatabaseError { operation: "find_one", with: "user" })?
|
||||||
|
.ok_or_else(|| Error::UnknownUser)?;
|
||||||
|
|
||||||
|
Ok(
|
||||||
|
from_bson(Bson::Document(doc))
|
||||||
|
.map_err(|_| Error::DatabaseError { operation: "from_bson", with: "user" })?
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'r> FromParam<'r> for Ref {
|
||||||
|
type Error = &'r RawStr;
|
||||||
|
|
||||||
|
fn from_param(param: &'r RawStr) -> Result<Self, Self::Error> {
|
||||||
|
if let Ok(result) = Ref::from(param.to_string()) {
|
||||||
|
if result.validate().is_ok() {
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(param)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ pub fn get_collection(collection: &str) -> Collection {
|
|||||||
get_db().collection(collection)
|
get_db().collection(collection)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub mod permissions;
|
||||||
pub mod migrations;
|
pub mod migrations;
|
||||||
pub mod entities;
|
pub mod entities;
|
||||||
pub mod guards;
|
pub mod guards;
|
||||||
|
|||||||
32
src/database/permissions/mod.rs
Normal file
32
src/database/permissions/mod.rs
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
use crate::database::entities::User;
|
||||||
|
use num_enum::TryFromPrimitive;
|
||||||
|
use std::ops;
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, TryFromPrimitive, Copy, Clone)]
|
||||||
|
#[repr(u32)]
|
||||||
|
pub enum UserPermission {
|
||||||
|
Access = 1,
|
||||||
|
SendMessage = 2,
|
||||||
|
Invite = 4
|
||||||
|
}
|
||||||
|
|
||||||
|
bitfield! {
|
||||||
|
pub struct UserPermissions(MSB0 [u32]);
|
||||||
|
u32;
|
||||||
|
pub get_access, _: 31;
|
||||||
|
pub get_send_message, _: 30;
|
||||||
|
pub get_invite, _: 29;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_op_ex!(+ |a: &UserPermission, b: &UserPermission| -> u32 { *a + *b });
|
||||||
|
impl_op_ex!(+ |a: &u32, b: &UserPermission| -> u32 { *a + *b });
|
||||||
|
|
||||||
|
pub async fn temp_calc_perm(_user: &User, _target: &User) -> UserPermissions<[u32; 1]> {
|
||||||
|
// if friends; Access + Message + Invite
|
||||||
|
// if mutually know each other:
|
||||||
|
// and has DMs from users enabled -> Access + Message
|
||||||
|
// otherwise -> Access
|
||||||
|
// otherwise; None
|
||||||
|
|
||||||
|
UserPermissions([UserPermission::Access + UserPermission::SendMessage + UserPermission::Invite])
|
||||||
|
}
|
||||||
@@ -7,6 +7,10 @@ extern crate rocket;
|
|||||||
extern crate rocket_contrib;
|
extern crate rocket_contrib;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate lazy_static;
|
extern crate lazy_static;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate impl_ops;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate bitfield;
|
||||||
extern crate ctrlc;
|
extern crate ctrlc;
|
||||||
|
|
||||||
pub mod notifications;
|
pub mod notifications;
|
||||||
|
|||||||
42
src/routes/users/fetch_dms.rs
Normal file
42
src/routes/users/fetch_dms.rs
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
use crate::database::entities::{Channel, User};
|
||||||
|
use mongodb::bson::{Bson, doc, from_bson};
|
||||||
|
use crate::util::result::{Error, Result};
|
||||||
|
use crate::database::get_collection;
|
||||||
|
use rocket_contrib::json::JsonValue;
|
||||||
|
use futures::StreamExt;
|
||||||
|
|
||||||
|
#[get("/dms")]
|
||||||
|
pub async fn req(user: User) -> Result<JsonValue> {
|
||||||
|
let mut cursor = get_collection("channels")
|
||||||
|
.find(
|
||||||
|
doc! {
|
||||||
|
"$or": [
|
||||||
|
{
|
||||||
|
"type": "DirectMessage",
|
||||||
|
"active": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "Group"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"recipients": user.id
|
||||||
|
},
|
||||||
|
None
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map_err(|_| Error::DatabaseError { operation: "find", with: "channels" })?;
|
||||||
|
|
||||||
|
let mut channels: Vec<Channel> = vec![];
|
||||||
|
while let Some(result) = cursor.next().await {
|
||||||
|
if let Ok(doc) = result {
|
||||||
|
channels.push(
|
||||||
|
from_bson(Bson::Document(doc))
|
||||||
|
.map_err(|_| Error::DatabaseError { operation: "from_bson", with: "channel" })?
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(json!(
|
||||||
|
channels
|
||||||
|
))
|
||||||
|
}
|
||||||
@@ -1,7 +1,22 @@
|
|||||||
use crate::util::result::Result;
|
use crate::database::guards::reference::Ref;
|
||||||
|
use crate::util::result::{Error, Result};
|
||||||
|
use crate::database::entities::User;
|
||||||
|
use rocket_contrib::json::JsonValue;
|
||||||
|
|
||||||
#[get("/<id>")]
|
#[get("/<target>")]
|
||||||
pub async fn req(id: String) -> Result<String> {
|
pub async fn req(user: User, target: Ref) -> Result<JsonValue> {
|
||||||
println!("{}", id);
|
let mut target = target.fetch_user().await?;
|
||||||
Ok("LETS FUCKING GOOOO".to_string())
|
|
||||||
|
if user.id != target.id {
|
||||||
|
// Check whether we are allowed to fetch this user.
|
||||||
|
let perm = crate::database::permissions::temp_calc_perm(&user, &target).await;
|
||||||
|
if !perm.get_access() {
|
||||||
|
Err(Error::LabelMe)?
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only return user relationships if the target is the caller.
|
||||||
|
target.relations = None;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(json!(target))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
use rocket::Route;
|
use rocket::Route;
|
||||||
|
|
||||||
mod fetch_user;
|
mod fetch_user;
|
||||||
|
mod fetch_dms;
|
||||||
|
|
||||||
pub fn routes() -> Vec<Route> {
|
pub fn routes() -> Vec<Route> {
|
||||||
routes! [
|
routes! [
|
||||||
fetch_user::req
|
fetch_user::req,
|
||||||
|
fetch_dms::req
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,9 @@ pub enum Error {
|
|||||||
#[snafu(display("Username has already been taken."))]
|
#[snafu(display("Username has already been taken."))]
|
||||||
#[serde(rename = "username_taken")]
|
#[serde(rename = "username_taken")]
|
||||||
UsernameTaken,
|
UsernameTaken,
|
||||||
|
#[snafu(display("This user does not exist!"))]
|
||||||
|
#[serde(rename = "unknown_user")]
|
||||||
|
UnknownUser,
|
||||||
|
|
||||||
// ? General errors.
|
// ? General errors.
|
||||||
#[snafu(display("Failed to validate fields."))]
|
#[snafu(display("Failed to validate fields."))]
|
||||||
@@ -74,6 +77,7 @@ impl<'r> Responder<'r, 'static> for Error {
|
|||||||
Error::DatabaseError { .. } => Status::InternalServerError,
|
Error::DatabaseError { .. } => Status::InternalServerError,
|
||||||
Error::FailedValidation { .. } => Status::UnprocessableEntity,
|
Error::FailedValidation { .. } => Status::UnprocessableEntity,
|
||||||
Error::LabelMe => Status::InternalServerError,
|
Error::LabelMe => Status::InternalServerError,
|
||||||
|
Error::UnknownUser => Status::NotFound,
|
||||||
Error::UsernameTaken => Status::Conflict,
|
Error::UsernameTaken => Status::Conflict,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user