Removal of chrono and async_trait as dependancy in db-lib

Removig chrono from api code as well

Removing chrono as dep in api code
+ Using Content-Type for /message/send content type

Updating cargo lists for removal of fluff deps

Removal of more fluff

Addking makefile to avoid compiling debug builds by accident while developing
This commit is contained in:
shockrah 2021-03-20 13:56:02 -07:00
parent cb5975f235
commit 988aa9f155
21 changed files with 181 additions and 2062 deletions

154
json-api/Cargo.lock generated
View File

@ -48,17 +48,6 @@ version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
[[package]]
name = "async-trait"
version = "0.1.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3340571769500ddef1e94b45055fabed6b08a881269b7570c830b8f32ef84ef"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "atty"
version = "0.2.14"
@ -193,9 +182,9 @@ checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7"
[[package]]
name = "byteorder"
version = "1.4.2"
version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae44d1a3d5a19df61dd0c8beb138458ac2a53a7ac09eba97d55592540004306b"
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]]
name = "bytes"
@ -363,11 +352,8 @@ dependencies = [
name = "db"
version = "0.1.0"
dependencies = [
"async-trait",
"chrono",
"mysql_async",
"serde",
"serde_json",
]
[[package]]
@ -482,21 +468,6 @@ version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
[[package]]
name = "futures"
version = "0.3.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f55667319111d593ba876406af7c409c0ebb44dc4be6132a783ccf163ea14c1"
dependencies = [
"futures-channel",
"futures-core",
"futures-executor",
"futures-io",
"futures-sink",
"futures-task",
"futures-util",
]
[[package]]
name = "futures-channel"
version = "0.3.13"
@ -504,7 +475,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c2dd2df839b57db9ab69c2c9d8f3e8c81984781937fe2807dc6dcf3b2ad2939"
dependencies = [
"futures-core",
"futures-sink",
]
[[package]]
@ -513,23 +483,6 @@ version = "0.3.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "15496a72fabf0e62bdc3df11a59a3787429221dd0710ba8ef163d6f7a9112c94"
[[package]]
name = "futures-executor"
version = "0.3.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "891a4b7b96d84d5940084b2a37632dd65deeae662c114ceaa2c879629c9c0ad1"
dependencies = [
"futures-core",
"futures-task",
"futures-util",
]
[[package]]
name = "futures-io"
version = "0.3.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d71c2c65c57704c32f5241c1223167c2c3294fd34ac020c807ddbe6db287ba59"
[[package]]
name = "futures-macro"
version = "0.3.13"
@ -560,13 +513,9 @@ version = "0.3.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1812c7ab8aedf8d6f2701a43e1243acdbcc2b36ab26e2ad421eb99ac963d96d1"
dependencies = [
"futures-channel",
"futures-core",
"futures-io",
"futures-macro",
"futures-sink",
"futures-task",
"memchr",
"pin-project-lite 0.2.6",
"pin-utils",
"proc-macro-hack",
@ -751,9 +700,9 @@ checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736"
[[package]]
name = "js-sys"
version = "0.3.48"
version = "0.3.49"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc9f84f9b115ce7843d60706df1422a916680bfdfcbdb0447c5614ff9d7e4d78"
checksum = "dc15e39392125075f60c95ba416f5381ff6c3a948ff02ab12464715adf56c821"
dependencies = [
"wasm-bindgen",
]
@ -764,11 +713,9 @@ version = "0.2.0"
dependencies = [
"base64 0.12.3",
"bcrypt",
"chrono",
"clap",
"db",
"dotenv",
"futures",
"getrandom 0.1.16",
"hyper",
"jsonwebtoken",
@ -777,10 +724,8 @@ dependencies = [
"rand 0.7.3",
"serde",
"serde_json",
"time 0.2.25",
"tokio",
"tokio-test",
"url",
]
[[package]]
@ -838,9 +783,9 @@ dependencies = [
[[package]]
name = "libc"
version = "0.2.88"
version = "0.2.90"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03b07a082330a35e43f63177cc01689da34fbffa0105e1246cf0311472cac73a"
checksum = "ba4aede83fc3617411dc6993bc8c70919750c1c257c6ca6a502aed6e0e2394ae"
[[package]]
name = "libz-sys"
@ -1009,13 +954,13 @@ dependencies = [
"num-bigint",
"num-traits",
"rand 0.7.3",
"regex 1.4.3",
"regex 1.4.5",
"rust_decimal",
"serde",
"serde_json",
"sha1",
"sha2",
"time 0.2.25",
"time 0.2.26",
"twox-hash",
"uuid",
]
@ -1115,15 +1060,15 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
[[package]]
name = "openssl"
version = "0.10.32"
version = "0.10.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "038d43985d1ddca7a9900630d8cd031b56e4794eecc2e9ea39dd17aa04399a70"
checksum = "a61075b62a23fef5a29815de7536d940aa35ce96d18ce0cc5076272db678a577"
dependencies = [
"bitflags",
"cfg-if 1.0.0",
"foreign-types",
"lazy_static",
"libc",
"once_cell",
"openssl-sys",
]
@ -1135,9 +1080,9 @@ checksum = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de"
[[package]]
name = "openssl-sys"
version = "0.9.60"
version = "0.9.61"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "921fc71883267538946025deffb622905ecad223c28efbfdef9bb59a0175f3e6"
checksum = "313752393519e876837e09e1fa183ddef0be7735868dced3196f4472d536277f"
dependencies = [
"autocfg",
"cc",
@ -1154,7 +1099,7 @@ checksum = "fd56cbd21fea48d0c440b41cd69c589faacade08c992d9a54e471b79d0fd13eb"
dependencies = [
"base64 0.13.0",
"once_cell",
"regex 1.4.3",
"regex 1.4.5",
]
[[package]]
@ -1362,20 +1307,19 @@ dependencies = [
"aho-corasick 0.6.10",
"memchr",
"regex-syntax 0.5.6",
"thread_local 0.3.6",
"thread_local",
"utf8-ranges",
]
[[package]]
name = "regex"
version = "1.4.3"
version = "1.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9251239e129e16308e70d853559389de218ac275b515068abc96829d05b948a"
checksum = "957056ecddbeba1b26965114e191d2e8589ce74db242b6ea25fc4062427a5c19"
dependencies = [
"aho-corasick 0.7.15",
"memchr",
"regex-syntax 0.6.22",
"thread_local 1.1.3",
"regex-syntax 0.6.23",
]
[[package]]
@ -1389,9 +1333,9 @@ dependencies = [
[[package]]
name = "regex-syntax"
version = "0.6.22"
version = "0.6.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5eb417147ba9860a96cfe72a0b93bf88fee1744b5636ec99ab20c1aa9376581"
checksum = "24d5f089152e60f62d28b835fbff2cd2e8dc0baf1ac13343bef92ab7eed84548"
[[package]]
name = "remove_dir_all"
@ -1467,9 +1411,9 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "security-framework"
version = "2.1.1"
version = "2.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dfd318104249865096c8da1dfabf09ddbb6d0330ea176812a62ec75e40c4166"
checksum = "d493c5f39e02dfb062cd8f33301f90f9b13b650e8c1b1d0fd75c19dd64bff69d"
dependencies = [
"bitflags",
"core-foundation",
@ -1597,9 +1541,9 @@ checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
[[package]]
name = "standback"
version = "0.2.15"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2beb4d1860a61f571530b3f855a1b538d0200f7871c63331ecd6f17b1f014f8"
checksum = "decebb311175fdaf1bf8a14583716e93163c566db2ead1c1d608c3e1e4313cb8"
dependencies = [
"version_check",
]
@ -1667,9 +1611,9 @@ checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
[[package]]
name = "syn"
version = "1.0.61"
version = "1.0.64"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed22b90a0e734a23a7610f4283ac9e5acfb96cbb30dfefa540d66f866f1c09c5"
checksum = "3fd9d1e9976102a03c542daa2eff1b43f9d72306342f3f8b3ed5fb8908195d6f"
dependencies = [
"proc-macro2",
"quote",
@ -1740,15 +1684,6 @@ dependencies = [
"lazy_static",
]
[[package]]
name = "thread_local"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8018d24e04c95ac8790716a5987d0fec4f8b27249ffa0f7d33f1369bdfb88cbd"
dependencies = [
"once_cell",
]
[[package]]
name = "time"
version = "0.1.43"
@ -1761,9 +1696,9 @@ dependencies = [
[[package]]
name = "time"
version = "0.2.25"
version = "0.2.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1195b046942c221454c2539395f85413b33383a067449d78aab2b7b052a142f7"
checksum = "08a8cbfbf47955132d0202d1662f49b2423ae35862aee471f3ba4b133358f372"
dependencies = [
"const_fn",
"libc",
@ -1826,7 +1761,6 @@ dependencies = [
"libc",
"memchr",
"mio",
"mio-named-pipes",
"mio-uds",
"num_cpus",
"pin-project-lite 0.1.12",
@ -1952,9 +1886,9 @@ dependencies = [
[[package]]
name = "typenum"
version = "1.12.0"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33"
checksum = "879f6906492a7cd215bfa4cf595b600146ccfac0c79bcbd1f3000162af5e8b06"
[[package]]
name = "ucd-util"
@ -2036,9 +1970,9 @@ checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
[[package]]
name = "version_check"
version = "0.9.2"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed"
checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
[[package]]
name = "want"
@ -2064,9 +1998,9 @@ checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
[[package]]
name = "wasm-bindgen"
version = "0.2.71"
version = "0.2.72"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ee1280240b7c461d6a0071313e08f34a60b0365f14260362e5a2b17d1d31aa7"
checksum = "8fe8f61dba8e5d645a4d8132dc7a0a66861ed5e1045d2c0ed940fab33bac0fbe"
dependencies = [
"cfg-if 1.0.0",
"wasm-bindgen-macro",
@ -2074,9 +2008,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.71"
version = "0.2.72"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b7d8b6942b8bb3a9b0e73fc79b98095a27de6fa247615e59d096754a3bc2aa8"
checksum = "046ceba58ff062da072c7cb4ba5b22a37f00a302483f7e2a6cdc18fedbdc1fd3"
dependencies = [
"bumpalo",
"lazy_static",
@ -2089,9 +2023,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.71"
version = "0.2.72"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5ac38da8ef716661f0f36c0d8320b89028efe10c7c0afde65baffb496ce0d3b"
checksum = "0ef9aa01d36cda046f797c57959ff5f3c615c9cc63997a8d545831ec7976819b"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
@ -2099,9 +2033,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.71"
version = "0.2.72"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc053ec74d454df287b9374ee8abb36ffd5acb95ba87da3ba5b7d3fe20eb401e"
checksum = "96eb45c1b2ee33545a813a92dbb53856418bf7eb54ab34f7f7ff1448a5b3735d"
dependencies = [
"proc-macro2",
"quote",
@ -2112,15 +2046,15 @@ dependencies = [
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.71"
version = "0.2.72"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d6f8ec44822dd71f5f221a5847fb34acd9060535c1211b70a05844c0f6383b1"
checksum = "b7148f4696fb4960a346eaa60bbfb42a1ac4ebba21f750f75fc1375b098d5ffa"
[[package]]
name = "web-sys"
version = "0.3.48"
version = "0.3.49"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec600b26223b2948cedfde2a0aa6756dcf1fef616f43d7b3097aaf53a6c4d92b"
checksum = "59fe19d70f5dacc03f6e46777213facae5ac3801575d56ca6cbd4c93dcd12310"
dependencies = [
"js-sys",
"wasm-bindgen",

View File

@ -6,25 +6,26 @@ edition = "2018"
[workspace]
[dependencies]
tokio = { version = "0.2", features=["full"] }
# Networking things
tokio = { version = "^0.2", features = ["rt-core", "rt-threaded", "macros", "signal"] }
hyper = "0.13"
futures = "0.3"
url = "2.1.1"
mysql_async = "0.23.1"
dotenv = "0.9.0"
chrono = "0.4.0"
time = "0.2"
# Crypto things
getrandom = "0.1"
bcrypt = "0.8"
base64 = "0.12.1"
rand = "0.7.3"
jsonwebtoken = "7.2.0"
# Cli args
clap = "2.32.2"
# Serialization
serde_json = "1.0"
serde = { version = "1.0.114", features = [ "derive" ] }
lazy_static = "1.4.0"

8
json-api/Makefile Normal file
View File

@ -0,0 +1,8 @@
default:
cargo build --release
dep:
cargo update
clean:
cargo clean

1576
json-api/db/Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -8,9 +8,6 @@ edition = "2018"
[dependencies]
mysql_async = "0.23.1"
async-trait = "0.1.40"
serde_json = "1.0"
serde = { version = "1.0.117", features = [ "derive" ] }
chrono = "0.4.0"

View File

@ -1,9 +1,3 @@
use mysql_async::Pool;
use async_trait::async_trait;
use crate::Response;
use crate::UBigInt;
#[macro_export]
macro_rules! no_conn {
($spec:literal) => {
@ -30,24 +24,3 @@ macro_rules! sql_err_log {
}
}
/*
* NOTE: pay attention to work on async in traits for rust
* Each of one these funcs will implicitly do a single heap allocation which
* for our case is fine though ideally we don't
*
* As soon as we finda way around that we should depecrate `#[async_trait`
* for the performance
* */
#[async_trait]
pub trait FromDB<T, FilterType> {
type Row;
async fn get(p: &Pool, id: UBigInt) -> Response<T>;
async fn update(p: &Pool, row: T) -> Response<T>;
async fn delete(p: &Pool, id: UBigInt) -> Response<T>;
async fn filter(p: &Pool, filter_val: FilterType) -> Response<T>;
}

View File

@ -1,132 +1,50 @@
use mysql_async::{params, Pool, Conn};
use std::time::{SystemTime, Duration, UNIX_EPOCH};
use mysql_async::{params, Pool};
use mysql_async::prelude::Queryable;
use mysql_async::error::Error as SqlError;
use serde::Serialize;
use async_trait::async_trait;
use crate::{BigInt, Invite, Response};
use crate::{UBigInt, BigInt};
use crate::common::FromDB;
use crate::{Response, no_conn};
#[allow(dead_code)]
#[derive(Serialize, Debug)]
pub struct Invite {
pub id: BigInt,
pub uses: Option<BigInt>,
pub expires: bool
}
#[async_trait]
impl FromDB<Invite, bool> for Invite {
type Row = Option<(BigInt, Option<BigInt>, bool)>;
async fn get(p: &Pool, id: UBigInt) -> Response<Self> {
impl Invite {
pub async fn get(p: &Pool, id: BigInt) -> Result<Response<Self>, SqlError> {
// NOTE: cast is required for this as `id` is used as unix timestamp
let id: BigInt = id as BigInt;
if id <= 0 {
return Response::Empty;
return Ok(Response::RestrictedInput(format!("<{}> not found", id)))
}
if let Ok(conn) = p.get_conn().await {
let q = "SELECT id, uses, expires FROM invites WHERE id = :id ";
let result: Result<(Conn, Self::Row), SqlError> =
conn.first_exec(q, params!{"id" => id}).await;
let conn = p.get_conn().await?;
let q = "SELECT uses, expires FROM invites WHERE id = :id ";
let (_, data_row): (_, Option<(Option<BigInt>, bool)>) =
conn.first_exec(q, params!{"id" => id}).await?;
if let Ok((_, row)) = result {
return match row {
Some(row) => Response::Row(Self {
id: id as BigInt,
uses: row.1,
expires: row.2
}),
None => Response::Empty
}
}
return if let Some(row) = data_row {
Ok(Response::Row(Invite{
id,
uses: row.0,
expires: row.1,
}))
} else {
Ok(Response::Empty)
}
return Response::Empty;
}
async fn update(p: &Pool, row: Self) -> Response<Self> {
let q = r#"UPDATE invites
SET uses = :uses, expires: :exp
WHERE id = :id
"#;
// forcibly udpate even if theres nothing there
// this way we avoid doing an extra network hit
if row.id <= 0 {
return Response::Empty;
}
if let Ok(conn) = p.get_conn().await {
let result: Result<Conn, SqlError> =
conn.drop_exec(q, params!{
"id" => row.id,
"uses" => row.uses,
"exp" => row.expires
}).await;
return match result {
Ok(_) => Response::Success,
Err(_) => Response::Other(format!("Could not update entry {}", row.id))
}
}
return Response::Empty;
}
async fn delete(p: &Pool, id: UBigInt) -> Response<Self> {
if id <= 0 { // really lame "assertion" that each method has to use for invites since they all internally use
return Response::Empty;
}
if let Ok(conn) = p.get_conn().await {
let q = "DELETE FROM invites WHERE id = :id";
let result: Result<Conn, SqlError> =
conn.drop_exec(q, params!{"id" => id as BigInt}).await;
return match result {
Ok(_) => Response::Success,
Err(_) => Response::Other(format!("Could not delete {}", id))
}
}
return Response::Success;
}
async fn filter(p: &Pool, expirey_flag: bool) -> Response<Self> {
if let Ok(conn) = p.get_conn().await {
let q = "SELECT id, uses, expires FROM invites WHERE expires = :exp";
if let Ok(query) = conn.prep_exec(q, params!{"exp" => expirey_flag}).await {
let mapping_r = query.map_and_drop(|row| {
let (id, uses): (BigInt, Option<BigInt>) = mysql_async::from_row(row);
Invite {
id,
uses,
expires: expirey_flag
}
}).await;
return match mapping_r {
Ok((_, invites)) => Response::Set(invites),
Err(_) => Response::Empty
}
}
else {
return Response::Other(no_conn!("db::Invite::filter"));
}
}
else {
return Response::Other(no_conn!("db::Invites::filter"));
}
}
}
impl Invite {
pub fn new(uses: Option<i64>, expires: bool) -> Invite {
use chrono::Utc;
// now + 30 minutes
let later = SystemTime::now() + Duration::from_secs(60 * 30);
let id: i64 = later.duration_since(UNIX_EPOCH).expect("honestly idk").as_millis() as i64;
Invite {
id: (Utc::now() + chrono::Duration::minutes(30)).timestamp_millis(),
id,
uses,
expires
}
}
pub async fn add(&self, p: &Pool) -> Result<(), SqlError> {
let conn = p.get_conn().await?;
@ -140,4 +58,5 @@ impl Invite {
Ok(())
}
}

View File

@ -66,13 +66,19 @@ pub struct Channel {
pub kind: Integer
}
#[macro_export]
macro_rules! fetch_row {
($table:literal, $col:literal, $key:expr, $rtype:ty,$conn:expr) => {
let lib_str = format!("SELECT * FROM {} WHERE {} = :{}", $table, $col, $col);
let (_, $rtype) = $conn.first_exec!(lib_str, sql_params{
$col => $key,
});
}
#[derive(Serialize, Debug)]
pub struct Invite {
pub id: BigInt,
pub uses: Option<BigInt>,
pub expires: bool
}
#[derive(Debug, Serialize)]
pub struct Member {
pub id: UBigInt,
pub secret: VarChar,
pub name: VarChar,
pub status: Integer,
pub permissions: UBigInt,
}

View File

@ -2,24 +2,12 @@ use mysql_async::{params, Pool, Conn};
use mysql_async::prelude::Queryable;
use mysql_async::error::Error as SqlError;
use async_trait::async_trait;
use serde::Serialize;
use crate::{Response, no_conn, sql_err};
use crate::{UBigInt, BigInt, Integer, VarChar};
use crate::{UBigInt, Integer, VarChar};
use crate::Member;
use crate::common::FromDB;
#[derive(Debug, Serialize)]
pub struct Member {
pub id: UBigInt,
pub secret: VarChar,
pub name: VarChar,
pub joindate: BigInt,
pub status: Integer,
pub permissions: UBigInt,
}
pub const STATUS_ONLINE: Integer = 0;
@ -33,16 +21,14 @@ pub const STATUS_DO_NOT_DISTURB: Integer = 3;
* return response based on result
*
*/
#[async_trait]
impl FromDB<Member, Integer> for Member {
type Row = Option<(VarChar, VarChar, BigInt, Integer, UBigInt)>;
async fn get(p: &Pool, id: UBigInt) -> Response<Self> {
impl Member {
pub async fn get(p: &Pool, id: UBigInt) -> Response<Self> {
//! @returns Row on success
//! @returns Other on failure
if let Ok(conn) = p.get_conn().await {
let q = "SELECT secret, name, joindate, status, permissions FROM members WHERE id = :id";
let db_res : Result<(Conn, Self::Row), SqlError>
let q = "SELECT secret, name, status, permissions FROM members WHERE id = :id";
type Row = Option<(VarChar, VarChar, Integer, UBigInt)>;
let db_res : Result<(Conn, Row), SqlError>
= conn.first_exec(q, params!{"id" => id}).await;
if let Ok((_, row)) = db_res {
return match row {
@ -50,9 +36,8 @@ impl FromDB<Member, Integer> for Member {
id,
secret: row.0,
name: row.1,
joindate: row.2,
status: row.3,
permissions: row.4
status: row.2,
permissions: row.3
}),
None => Response::Empty
}
@ -62,52 +47,8 @@ impl FromDB<Member, Integer> for Member {
return Response::Other(no_conn!("Member::FromDB::get"));
}
async fn update(p: &Pool, row: Member) -> Response<Self> {
let q = r#"UPDATE members
SET status = :status, permissions = :perms, name = :name
WHERE id = :id"#;
if let Ok(conn) = p.get_conn().await {
let query = conn.drop_exec(q, params!{
"id" => row.id,
"status" => row.status,
"name" => row.name,
"perms" => row.permissions
}).await;
return match query {
Ok(_) => Response::Success,
Err(err) => Response::Other(sql_err!(err))
}
}
return Response::Other(no_conn!("db::Member::update"));
}
async fn delete(p: &Pool, id: UBigInt) -> Response<Self> {
if let Ok(conn) = p.get_conn().await {
let q = "DELETE from members WHERE id = :id";
let db_result: Result<Conn, SqlError>
= conn.drop_exec(q, params!{"id" => id}).await;
match Member::get(p, id).await {
Response::Row(_) => {
if let Ok(conn) = db_result {
return match conn.prep_exec("", params!{"id" => id}).await {
Ok(_) => Response::Success,
Err(_) => Response::Other(sql_err!("Member::FromDB::delete"))
}
}
return Response::Success
},
Response::Empty => return Response::Empty,
_ => return Response::Other(sql_err!("Member::FromDB::delete | another stupid get happened delid this"))
}
}
return Response::Empty;
}
async fn filter(p: &Pool, status: Integer) -> Response<Self> {
pub async fn filter(p: &Pool, status: Integer) -> Response<Self> {
//! @params status
return match (p.get_conn().await, status) {
(Ok(conn), STATUS_ONLINE) | (Ok(conn), STATUS_OFFLINE) |
@ -127,7 +68,6 @@ impl FromDB<Member, Integer> for Member {
id,
secret: "".into(), // no show for obv reasons
name,
joindate: 0, // doesn't matter
status,
permissions
}
@ -144,9 +84,6 @@ impl FromDB<Member, Integer> for Member {
_ => Response::Other(sql_err!("err"))
}
}
}
impl Member {
pub async fn add(p: &Pool, name: &str, secret: &str, perms: u64) -> Result<Response<Self>, SqlError> {
//! @param {pool} p
//! @param {&str} name of new user
@ -156,23 +93,15 @@ impl Member {
//! @returns : on_succes => Ok(Response<Member>)
//! @returns : on_partial_succes => Ok(Response<Member>)
//! @returns : on_failure => Err(SomeBS)
use chrono::Utc;
let conn = p.get_conn().await?;
//name
//perms
//secret
let now: BigInt = Utc::now().timestamp();
let conn = conn.drop_exec(
"INSERT INTO members(secret, name, joindate, status, permissions)
VALUES(:secret, :name, :joindate, :status, :permissions)",
"INSERT INTO members(secret, name, status, permissions)
VALUES(:secret, :name, :status, :permissions)",
mysql_async::params!{
"secret" => secret.clone(),
"name" => name.clone(),
"joindate" => now,
"status" => STATUS_ONLINE,
"permissions" => perms
}).await?;
@ -188,7 +117,6 @@ impl Member {
id,
secret: secret.into(),
name: name.into(),
joindate: now,
status: STATUS_ONLINE,
permissions: perms
}))

View File

@ -1,3 +1,5 @@
use std::time::{SystemTime, UNIX_EPOCH};
use mysql_async::{params, Pool};
use mysql_async::prelude::Queryable;
use mysql_async::error::Error as SqlError;
@ -5,22 +7,25 @@ use mysql_async::error::Error as SqlError;
use crate::{Response, sql_err};
use crate::{UBigInt, BigInt, VarChar};
use crate::UserMessage;
use crate::{Message, UserMessage};
const MAX_MESSAGES: u64 = 1000;
impl crate::Message {
impl Message {
pub async fn send(p: &Pool, content: &str, content_type: &str, cid: UBigInt, uid: UBigInt) -> Result<Response<Self>, SqlError> {
//! @returns on_sucess -> empty
//! @returns on_failure Err(SqlErr)
use chrono::Utc;
let conn = p.get_conn().await?;
let q = "INSERT INTO messages
(time, content, content_type, author_id, channel_id)
VALUES (:time, :content, :ctype, :author, :channel)";
let now = Utc::now().timestamp();
let now: i64 = SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("System time `NOW` failed")
.as_millis() as i64;
let res = conn.prep_exec(q, params!{
"time" => now,

View File

@ -9,10 +9,7 @@ use std::collections::HashMap;
use crate::perms::ADMIN_PERMS;
use db::{
self,
member::Member
};
use db::{self, Member};
use crate::qs_param;

View File

@ -1,15 +1,14 @@
use serde::{Serialize, Deserialize};
use bcrypt::{self, BcryptResult};
use mysql_async::Pool;
use chrono::{Utc, Duration};
use std::collections::HashMap;
use std::time::{SystemTime, UNIX_EPOCH};
use crate::routes;
use crate::qs_param;
use db::{member::Member, common::FromDB};
use db::Response;
use db::{Response, Member};
use jsonwebtoken::EncodingKey;
lazy_static! {
@ -31,12 +30,14 @@ struct Claim {
impl Claim {
pub fn new(id: db::UBigInt) -> Claim {
let now = SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("System time fetch failed")
.as_millis() as i64;
Claim {
sub: id,
exp: Utc::now()
.checked_add_signed(Duration::weeks(1))
.expect("Couldn't generate an expirey date")
.timestamp(),
exp: now,
cookie: generate_cookie()
}
}
@ -114,10 +115,14 @@ async fn valid_jwt(p: &Pool, token: &str) -> AuthReason {
let algo = Algorithm::HS512;
let dk = DecodingKey::from_secret(&HMAC_SECRET);
if let Ok(decoded) = decode::<Claim>(token, &dk, &Validation::new(algo)) {
let now = SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("System time fetch failed")
.as_millis() as i64;
// subject used for querying speed NOT security
let listed = db::auth::listed_jwt(p, decoded.claims.sub, token).await.unwrap();
let active = Utc::now().timestamp() < decoded.claims.exp;
let active = now < decoded.claims.exp;
return match listed && active {
true => AuthReason::Good,

View File

@ -6,7 +6,7 @@ use serde_json::json;
use std::collections::HashMap;
use db::{ self, common::FromDB, Channel };
use db::{ self, Channel};
use crate::http::set_json_body;
use crate::qs_param;
@ -80,7 +80,7 @@ pub async fn delete_channel(pool: &Pool, response: &mut Response<Body>, params:
* @channel_id : u64 - required
*/
use crate::perms;
use db::member::Member;
use db::Member;
use db::Response::*;
let uid = qs_param!(params, "id", u64).unwrap();

View File

@ -1,22 +1,11 @@
use serde_json::json;
use mysql_async;
use mysql_async::Pool;
use hyper::{Response, Body, StatusCode};
use chrono::Utc;
use std::time::{SystemTime, UNIX_EPOCH};
use std::collections::HashMap;
use db::BigInt;
use db::common::FromDB;
use db::member::Member;
use db::invites::Invite;
use crate::qs_param;
use crate::http;
use crate::meta;
use serde_json::json;
use mysql_async::{self, Pool};
use hyper::{Response, Body, StatusCode};
use db::{BigInt, Member, Invite};
use crate::{http, meta, qs_param};
/*
@ -29,15 +18,23 @@ async fn valid_invite(pool: &Pool, id: BigInt) -> bool {
/*
* Fetches an invite from the database to check for validity
*/
let query: Option<db::invites::Invite> = match db::invites::Invite::get(pool, id as u64).await {
db::Response::Row(invite) => { Some(invite) },
_ => { None }
let query = if let Ok(inv) = Invite::get(pool, id).await {
match inv {
db::Response::Row(data) => Some(data),
_ => None
}
} else {
None
};
if let Some(invite) = query {
// if expires at all
if invite.expires {
let now = Utc::now().timestamp_millis();
let now: i64 = SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("Systemtime fetch failed")
.as_millis() as i64;
// old?
let mut valid_status = now < invite.id;
// used?
@ -70,7 +67,7 @@ async fn use_invite(pool: &Pool, code: Option<BigInt>) -> Option<Member>{
if valid_invite(pool, id).await {
let raw_secret = auth::generate_secret();
let secret = auth::encrypt_secret(&raw_secret).unwrap();
return match db::member::Member::add(pool, "Anonymous".into(), &secret, GENERAL_NEW).await {
return match Member::add(pool, "Anonymous".into(), &secret, GENERAL_NEW).await {
Ok(response) => {
match response {
db::Response::Row(member) => Some(member),
@ -123,7 +120,7 @@ pub async fn join(pool: &Pool, response: &mut Response<Body>, params: HashMap<St
async fn allowed_perm_invite(pool: &Pool, uid: u64) -> bool {
use crate::perms;
return match db::member::Member::get(pool, uid).await {
return match Member::get(pool, uid).await {
db::Response::Row(user) => perms::has_perm(user.permissions, perms::CREATE_PERM_INVITES),
_ => false
};

View File

@ -1,5 +1,4 @@
extern crate db;
extern crate chrono;
extern crate clap;
extern crate dotenv;
extern crate getrandom;
@ -20,7 +19,8 @@ use hyper::{
Server,
Response, Request, Body,
Method, StatusCode,
service::{make_service_fn, service_fn}
service::{make_service_fn, service_fn},
HeaderMap
};
use mysql_async::Pool;
@ -51,11 +51,13 @@ async fn route_dispatcher(
meth: &Method,
path: &str,
body: Body,
params: HashMap<String, String>) {
params: HashMap<String, String>,
headers: HeaderMap) {
const GET: &Method = &Method::GET;
const POST: &Method = &Method::POST;
const DELETE: &Method = &Method::DELETE;
println!("{}: {}", meth, path);
match (meth, path) {
/* INVITES */
(POST, routes::INVITE_CREATE) => invites::create(pool, resp, params).await,
@ -65,7 +67,7 @@ async fn route_dispatcher(
(POST, routes::CHANNELS_CREATE) => channels::create_channel(pool, resp, params).await,
(DELETE, routes::CHANNELS_DELETE) => channels::delete_channel(pool, resp, params).await,
/* MESSAGING */
(POST, routes::MESSAGE_SEND) => messages::send_message(pool, resp, body, params).await,
(POST, routes::MESSAGE_SEND) => messages::send_message(pool, resp, body, headers, params).await,
(GET, routes::MESSAGE_TIME_RANGE) => messages::get_by_time(pool, resp, params).await,
(GET, routes::MESSAGE_FROM_ID) =>messages::from_id(pool, resp, params).await,
/* ADMIN */
@ -94,6 +96,7 @@ async fn main_responder(request: Request<Body>) -> Result<Response<Body>, hyper:
let method = parts.method;
let path = parts.uri.path();
let qs = parts.uri.query();
let headers = parts.headers;
let params_opt: Option<HashMap<String, String>> = if let Some(query_string) = qs {
Some(http::parse_query_string(query_string))
} else {
@ -103,7 +106,7 @@ async fn main_responder(request: Request<Body>) -> Result<Response<Body>, hyper:
if let Some(params) = params_opt {
let mysql_pool = Pool::new(&env::var("DATABASE_URL").unwrap());
match auth::wall_entry(path, &mysql_pool, &params).await {
OpenAuth | Good => route_dispatcher(&mysql_pool, &mut response, &method, path, body, params).await,
OpenAuth | Good => route_dispatcher(&mysql_pool, &mut response, &method, path, body, params, headers).await,
LoginValid => auth::login_get_jwt(&mysql_pool, &mut response, params).await,
NoKey | BadKey => *response.status_mut() = StatusCode::UNAUTHORIZED,
ServerIssue(msg) => {
@ -155,7 +158,7 @@ async fn attempt_owner_creation(name: &str) {
let p = Pool::new(&env::var("DATABASE_URL").unwrap());
let owner_secret = auth::generate_secret();
if let Ok(enc_secret) = auth::encrypt_secret(&owner_secret) {
if let Ok(response) = db::member::Member::add(&p, name, &enc_secret, perms::OWNER).await {
if let Ok(response) = db::Member::add(&p, name, &enc_secret, perms::OWNER).await {
match response {
db::Response::Row(mut owner) => {
owner.secret = owner_secret; // giving the secret itself back to the user

View File

@ -4,8 +4,7 @@ use mysql_async::Pool;
use serde_json::json;
use db::member::STATUS_ONLINE;
use db::common::FromDB;
use db::member::Member;
use db::Member;
use db::Response::*;
use crate::http::set_json_body;
@ -36,7 +35,6 @@ pub async fn get_self(p: &Pool, response: &mut Response<Body>, params: HashMap<S
set_json_body(response, json!({
"id" : user.id,
"name" : user.name,
"joindate" : user.joindate,
"permissions" : user.permissions
}));
},
@ -82,7 +80,6 @@ pub async fn get_member(p: &Pool, response: &mut Response<Body>, params: HashMap
set_json_body(response, json!({"member": {
"id": member.id,
"name": member.name,
"joindate": member.joindate,
"status": member.status,
"permissions": member.permissions
}}));

View File

@ -1,5 +1,5 @@
use mysql_async::Pool;
use hyper::{Response, Body, StatusCode};
use hyper::{Response, Body, HeaderMap, StatusCode};
use hyper::body::to_bytes;
use serde_json::json;
@ -54,19 +54,27 @@ pub async fn get_by_time(pool: &Pool, response: &mut Response<Body>, params: Has
}
}
pub async fn send_message(pool: &Pool, response: &mut Response<Body>, body: Body, params: HashMap<String, String>) {
pub async fn send_message(pool: &Pool, response: &mut Response<Body>, body: Body, headers: HeaderMap, params: HashMap<String, String>) {
/*
* Message content is sent in the message body
* @channel_id: channel id that we're going to send a message to
* @content-type in the headers
* TODO: more features here because send_message is a large handler
*/
use db::Response::*;
use db::member::Member;
use crate::db::common::FromDB;
use db::Member;
// NOTE: auth module guarantees this will be there in the correct form
// NOTE: auth module guarantees that id will be present so the unwrap is safe
let uid = qs_param!(params, "id", u64).unwrap();
let ctype = params.get("type");
let ctype: Option<&str> = match headers.get("Content-Type") {
Some(hval) => {
match hval.to_str() {
Ok(s) => Some(s),
_ => None
}
},
None => None
};
let permissions = match Member::get(pool, uid).await {
Row(user) => user.permissions,
@ -89,10 +97,11 @@ pub async fn send_message(pool: &Pool, response: &mut Response<Body>, body: Body
} else {
// block away wrong content types
const CONTENT_TYPES: [&'static str;7] = ["text", "png", "jpeg", "jpg", "webm", "mp3", "mp4"];
if CONTENT_TYPES.contains(&ctype.unwrap().as_str()) == false {
if CONTENT_TYPES.contains(&ctype.unwrap()) == false {
*response.status_mut() = StatusCode::BAD_REQUEST;
}
else {
// ctype safe unwrap
match db::Message::send(pool, &content, ctype.unwrap(), channel_id.unwrap(), uid).await {
Ok(Empty) => {/* TODO: put something here to notify the rtc server if its there*/},
Ok(RestrictedInput(_msg)) => *response.status_mut() = StatusCode::BAD_REQUEST,

View File

@ -1,18 +0,0 @@
server {
# Freechat servers should not bother adding support for unencrypted trafic
listen 443 ssl; # default_server;
listen [::]:443 ssl; # default_server;
# Uncomment this line if you are self signing your certs
#include snippets/self-signed.conf;
# General SSL/TLS settings for nginx
include snippets/ssl-params.conf;
server_name _;
location / {
proxy_pass http://0.0.0.0:4536;
}
}

View File

@ -1,42 +0,0 @@
# Configs for Nginx Reverse Proxy
The above are ultra minimal configs for setting up nginx.
# For self signing
_I'll be using openssl and summarizing the Digital OCean tutorial._ [Reference](https://www.digitalocean.com/community/tutorials/how-to-create-a-self-signed-ssl-certificate-for-nginx-in-ubuntu-16-04)
1. First you will have to generate a self-signed key and certificate pair.
```
openssl req -x509 -nodes -days 365 -newkey:2048 -keyout /etc/ssl/private/freechat.key -out /etc/ssl/certs/freechat.crt
```
2. Next create the Diffie-Hellman group file:
```
openssl dhparam -out /detc/ssl/certs/freechat.pem 2048
```
3. Next we should setup the configs for Nginx
* Place self-signed.conf into `/etc/nginx/snippets`.
This file tells nginx to use the previously created self signed certificates.
* Place ssl-params.conf into `/etc/nginx/snippets`.
This file is pretty general so if you're not self signing you can still use it as just configures TLS and SSL for Nginx.
4. After that you should be ready to start the server.
# Final Notes
Keep in mind will be able to access json-api endpoints with https://domain.net:<port> and without the port number attached. If you wish to restrict then I suggest restricting clients to _force the port number_ as all clients should be configured to do so anyway.
# Suggestions?
If something here seems wrong or needs fixing/updating/correcting feel free to open an issue.

View File

@ -1,4 +0,0 @@
# This should only be used if you are planning on self signing
ssl_certificate /etc/ssl/certs/freechat.crt;
ssl_certificate_key /etc/ssl/private/freechat.key;

View File

@ -1,20 +0,0 @@
ssl_protocols TLSv1 TLSV1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
ssl_ecdh_curve secp384r1;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
# Disable preloading HSTS for now. You can use the commented out header line that includes
# the "preload" directive if you understand the implications.
#add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload";
add_header Strict-Transport-Security "max-age=63072000; includeSubdomains";
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
# literal misspelling
ssl_dhparam /etc/ssl/certs/nginx-dev.pem;