Update crates and change to UUID
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,3 +1,2 @@
|
|||||||
/target
|
/target
|
||||||
/.idea
|
/.idea
|
||||||
Cargo.lock
|
|
||||||
|
1675
Cargo.lock
generated
Normal file
1675
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
27
Cargo.toml
27
Cargo.toml
@ -10,19 +10,22 @@ edition = "2018"
|
|||||||
hyper = { version = "0.14", features = ["full"] }
|
hyper = { version = "0.14", features = ["full"] }
|
||||||
tokio = { version = "1", features = ["full"] }
|
tokio = { version = "1", features = ["full"] }
|
||||||
futures = "0.3"
|
futures = "0.3"
|
||||||
tokio-tls = "0.3.1"
|
tokio-tls = "0.3"
|
||||||
rustls = "0.19.1"
|
rustls = "0.20"
|
||||||
tokio-rustls = "0.22.0"
|
rustls-pemfile = "1.0"
|
||||||
futures-util = "0.3.15"
|
tokio-rustls = "0.23"
|
||||||
async-stream = "0.3.2"
|
futures-util = "0.3"
|
||||||
hyper-tungstenite = "0.3.2"
|
async-stream = "0.3"
|
||||||
|
hyper-tungstenite = "0.8"
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
serde_json = "1.0.64"
|
serde_json = "1.0"
|
||||||
chrono = "0.4"
|
chrono = "0.4"
|
||||||
bb8 = "0.7.0"
|
tokio-postgres = { version = "0.7", features = ["with-uuid-1"] }
|
||||||
bb8-postgres = "0.7.0"
|
bb8 = "0.8"
|
||||||
|
bb8-postgres = "0.8"
|
||||||
ansi_term = "0.12"
|
ansi_term = "0.12"
|
||||||
rust-crypto = "^0.2"
|
rust-crypto = "^0.2"
|
||||||
base64 = "0.13.0"
|
base64 = "0.13"
|
||||||
base64-url = "1.4.10"
|
base64-url = "1.4"
|
||||||
rand = "0.8.3"
|
rand = "0.8"
|
||||||
|
uuid = { version = "1.1", features = ["v4", "serde", "fast-rng"] }
|
||||||
|
142
db/00.create.sql
142
db/00.create.sql
@ -3,47 +3,42 @@ CREATE DATABASE locutus;
|
|||||||
|
|
||||||
\c locutus
|
\c locutus
|
||||||
|
|
||||||
\set id_regex '''^[A-Za-z0-9_-]{43}$'''
|
CREATE TABLE domain
|
||||||
|
|
||||||
CREATE TABLE domains
|
|
||||||
(
|
(
|
||||||
domain_id CHAR(43) NOT NULL,
|
domain_id UUID NOT NULL,
|
||||||
domain_name VARCHAR(256) NOT NULL,
|
domain_name TEXT NOT NULL,
|
||||||
|
|
||||||
CONSTRAINT pk_domains PRIMARY KEY (domain_id),
|
CONSTRAINT pk_domain PRIMARY KEY (domain_id),
|
||||||
CONSTRAINT sk_domains UNIQUE (domain_name),
|
CONSTRAINT sk_domain UNIQUE (domain_name),
|
||||||
CONSTRAINT domains_domain_name CHECK (domain_name ~ '^([a-z0-9_-]+\.)+[a-z]{2,}$'),
|
CONSTRAINT domain_domain_name CHECK (domain_name ~ '^([a-z0-9_-]+\.)+[a-z]{2,}$')
|
||||||
CONSTRAINT domains_domain_id CHECK (domain_id ~ :id_regex)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE accounts
|
CREATE TABLE account
|
||||||
(
|
(
|
||||||
account_id CHAR(43) NOT NULL,
|
account_id UUID NOT NULL,
|
||||||
domain_id CHAR(43) NOT NULL,
|
domain_id UUID NOT NULL,
|
||||||
account_name VARCHAR(256) NOT NULL,
|
account_name TEXT NOT NULL,
|
||||||
|
|
||||||
CONSTRAINT pk_accounts PRIMARY KEY (account_id),
|
CONSTRAINT pk_account PRIMARY KEY (account_id),
|
||||||
CONSTRAINT sk_accounts UNIQUE (domain_id, account_name),
|
CONSTRAINT sk_account UNIQUE (domain_id, account_name),
|
||||||
CONSTRAINT fk_accounts_domains FOREIGN KEY (domain_id) REFERENCES domains (domain_id),
|
CONSTRAINT fk_account_domains FOREIGN KEY (domain_id) REFERENCES domain (domain_id)
|
||||||
CONSTRAINT accounts_account_id CHECK (account_id ~ :id_regex)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE rooms
|
CREATE TABLE room
|
||||||
(
|
(
|
||||||
room_id CHAR(43) NOT NULL,
|
room_id UUID NOT NULL,
|
||||||
room_name VARCHAR(256),
|
room_name TEXT,
|
||||||
|
|
||||||
CONSTRAINT pk_rooms PRIMARY KEY (room_id),
|
CONSTRAINT pk_room PRIMARY KEY (room_id)
|
||||||
CONSTRAINT rooms_room_id CHECK (room_id ~ :id_regex)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE events
|
CREATE TABLE event
|
||||||
(
|
(
|
||||||
event_id CHAR(43) NOT NULL,
|
event_id UUID NOT NULL,
|
||||||
room_id CHAR(43) NOT NULL,
|
room_id UUID NOT NULL,
|
||||||
from_member_id CHAR(43) NOT NULL,
|
from_member_id UUID NOT NULL,
|
||||||
from_session_id CHAR(43) NOT NULL,
|
from_session_id UUID NOT NULL,
|
||||||
to_session_id CHAR(43) DEFAULT NULL,
|
to_session_id UUID DEFAULT NULL,
|
||||||
|
|
||||||
client_ts TIMESTAMP WITHOUT TIME ZONE DEFAULT NULL,
|
client_ts TIMESTAMP WITHOUT TIME ZONE DEFAULT NULL,
|
||||||
client_tz INTEGER DEFAULT NULL,
|
client_tz INTEGER DEFAULT NULL,
|
||||||
@ -54,46 +49,41 @@ CREATE TABLE events
|
|||||||
|
|
||||||
data JSONB NOT NULL,
|
data JSONB NOT NULL,
|
||||||
|
|
||||||
CONSTRAINT pk_events PRIMARY KEY (event_id),
|
CONSTRAINT pk_event PRIMARY KEY (event_id),
|
||||||
CONSTRAINT sk_events UNIQUE (room_id, event_id),
|
CONSTRAINT sk_event UNIQUE (room_id, event_id),
|
||||||
CONSTRAINT fk_events_rooms FOREIGN KEY (room_id) REFERENCES rooms (room_id),
|
CONSTRAINT fk_event_rooms FOREIGN KEY (room_id) REFERENCES room (room_id)
|
||||||
CONSTRAINT events_event_id CHECK (event_id ~ :id_regex),
|
|
||||||
CONSTRAINT events_from_member_id CHECK (from_member_id ~ :id_regex),
|
|
||||||
CONSTRAINT events_from_session_id CHECK (from_session_id ~ :id_regex),
|
|
||||||
CONSTRAINT events_to_session_id CHECK (to_session_id ~ :id_regex)
|
|
||||||
);
|
);
|
||||||
CREATE INDEX idx_events_client_ts ON events (client_ts);
|
CREATE INDEX idx_event_client_ts ON event (client_ts);
|
||||||
CREATE INDEX idx_events_server_ts ON events (server_ts);
|
CREATE INDEX idx_event_server_ts ON event (server_ts);
|
||||||
CREATE INDEX idx_events_domain_ts ON events (domain_ts);
|
CREATE INDEX idx_event_domain_ts ON event (domain_ts);
|
||||||
|
|
||||||
CREATE TABLE members
|
CREATE TABLE member
|
||||||
(
|
(
|
||||||
member_id CHAR(43) NOT NULL,
|
member_id UUID NOT NULL,
|
||||||
domain_id CHAR(43) NOT NULL,
|
domain_id UUID NOT NULL,
|
||||||
room_id CHAR(43) NOT NULL,
|
room_id UUID NOT NULL,
|
||||||
account_id CHAR(43),
|
account_id UUID,
|
||||||
last_event_domain CHAR(43),
|
last_event_domain UUID,
|
||||||
last_event_session CHAR(43),
|
last_event_session UUID,
|
||||||
last_event_read CHAR(43),
|
last_event_read UUID,
|
||||||
|
|
||||||
CONSTRAINT pk_members PRIMARY KEY (member_id),
|
CONSTRAINT pk_member PRIMARY KEY (member_id),
|
||||||
CONSTRAINT sk_members UNIQUE (member_id, room_id),
|
CONSTRAINT sk_member UNIQUE (member_id, room_id),
|
||||||
CONSTRAINT fk_members_domains FOREIGN KEY (domain_id) REFERENCES domains (domain_id),
|
CONSTRAINT fk_member_domain FOREIGN KEY (domain_id) REFERENCES domain (domain_id),
|
||||||
CONSTRAINT fk_members_rooms FOREIGN KEY (room_id) REFERENCES rooms (room_id),
|
CONSTRAINT fk_member_room FOREIGN KEY (room_id) REFERENCES room (room_id),
|
||||||
CONSTRAINT fk_members_accounts FOREIGN KEY (account_id) REFERENCES accounts (account_id),
|
CONSTRAINT fk_member_account FOREIGN KEY (account_id) REFERENCES account (account_id),
|
||||||
CONSTRAINT fk_members_last_event_domain FOREIGN KEY (room_id, last_event_domain) REFERENCES events (room_id, event_id),
|
CONSTRAINT fk_member_last_event_domain FOREIGN KEY (room_id, last_event_domain) REFERENCES event (room_id, event_id),
|
||||||
CONSTRAINT fk_members_last_event_session FOREIGN KEY (room_id, last_event_session) REFERENCES events (room_id, event_id),
|
CONSTRAINT fk_member_last_event_session FOREIGN KEY (room_id, last_event_session) REFERENCES event (room_id, event_id),
|
||||||
CONSTRAINT fk_members_last_event_read FOREIGN KEY (room_id, last_event_read) REFERENCES events (room_id, event_id),
|
CONSTRAINT fk_member_last_event_read FOREIGN KEY (room_id, last_event_read) REFERENCES event (room_id, event_id)
|
||||||
CONSTRAINT members_member_id CHECK (member_id ~ :id_regex)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE sessions
|
CREATE TABLE session
|
||||||
(
|
(
|
||||||
session_id CHAR(43) NOT NULL,
|
session_id UUID NOT NULL,
|
||||||
account_id CHAR(43) NOT NULL,
|
account_id UUID NOT NULL,
|
||||||
session_nr INTEGER NOT NULL DEFAULT 1,
|
session_nr INTEGER NOT NULL DEFAULT 1,
|
||||||
session_token VARCHAR(256) NOT NULL,
|
session_token TEXT NOT NULL,
|
||||||
session_name VARCHAR(256) DEFAULT NULL,
|
session_name TEXT DEFAULT NULL,
|
||||||
active BOOLEAN NOT NULL DEFAULT TRUE,
|
active BOOLEAN NOT NULL DEFAULT TRUE,
|
||||||
|
|
||||||
first_used TIMESTAMP WITHOUT TIME ZONE NOT NULL DEFAULT (now() at time zone 'utc'),
|
first_used TIMESTAMP WITHOUT TIME ZONE NOT NULL DEFAULT (now() at time zone 'utc'),
|
||||||
@ -101,26 +91,26 @@ CREATE TABLE sessions
|
|||||||
last_used TIMESTAMP WITHOUT TIME ZONE NOT NULL DEFAULT (now() at time zone 'utc'),
|
last_used TIMESTAMP WITHOUT TIME ZONE NOT NULL DEFAULT (now() at time zone 'utc'),
|
||||||
last_used_tz INTEGER DEFAULT NULL,
|
last_used_tz INTEGER DEFAULT NULL,
|
||||||
|
|
||||||
CONSTRAINT pk_sessions PRIMARY KEY (session_id),
|
CONSTRAINT pk_session PRIMARY KEY (session_id),
|
||||||
CONSTRAINT sk_sessions_1 UNIQUE (account_id, session_nr),
|
CONSTRAINT sk_session_1 UNIQUE (account_id, session_nr),
|
||||||
CONSTRAINT sk_sessions_2 UNIQUE (session_token),
|
CONSTRAINT sk_session_2 UNIQUE (session_token),
|
||||||
CONSTRAINT fk_sessions_accounts FOREIGN KEY (account_id) REFERENCES accounts (account_id)
|
CONSTRAINT fk_session_account FOREIGN KEY (account_id) REFERENCES account (account_id)
|
||||||
);
|
);
|
||||||
|
|
||||||
INSERT INTO domains (domain_id, domain_name)
|
INSERT INTO domain (domain_id, domain_name)
|
||||||
VALUES ('wk2jFJku_7VvpM2hFIz2XBO0Yka9tLHwc6V0Yk8oYLA', 'necronda.net');
|
VALUES ('fe1b106c-18bc-4f85-943e-4950e0f3eb4f', 'necronda.net');
|
||||||
|
|
||||||
INSERT INTO accounts (account_id, domain_id, account_name)
|
INSERT INTO account (account_id, domain_id, account_name)
|
||||||
VALUES ('g_Ip_bkfpfT73USemt16PCyGcLKBkPmclVjsrKv51Po', 'wk2jFJku_7VvpM2hFIz2XBO0Yka9tLHwc6V0Yk8oYLA', 'lorenz'),
|
VALUES ('5c5dfc88-83f1-4933-b5cc-4a48eb735bfd', 'fe1b106c-18bc-4f85-943e-4950e0f3eb4f', 'lorenz'),
|
||||||
('X1j7UKLCwMTB3DbTuZvJxOBGoVDnApCjI894yAE7RFc', 'wk2jFJku_7VvpM2hFIz2XBO0Yka9tLHwc6V0Yk8oYLA', 'tom');
|
('87fdbcb7-1e87-4cbf-a792-5dfb13457423', 'fe1b106c-18bc-4f85-943e-4950e0f3eb4f', 'tom');
|
||||||
|
|
||||||
INSERT INTO rooms (room_id, room_name)
|
INSERT INTO room (room_id, room_name)
|
||||||
VALUES ('60nc0XXDIYUh6QzX4p0rMpCdzDmxghZLZk8dLuQh628', NULL);
|
VALUES ('24595934-4540-4333-ac2b-78796ac3f25f', NULL);
|
||||||
|
|
||||||
INSERT INTO members (member_id, domain_id, room_id, account_id)
|
INSERT INTO member (member_id, domain_id, room_id, account_id)
|
||||||
VALUES ('AbyhKNXgv4FDsm5Iq2p0RSHZr0cJ1ueBDL0UDMnV__4', 'wk2jFJku_7VvpM2hFIz2XBO0Yka9tLHwc6V0Yk8oYLA',
|
VALUES ('e735a9df-c55e-47d0-89d5-7a898162d6b9', 'fe1b106c-18bc-4f85-943e-4950e0f3eb4f',
|
||||||
'60nc0XXDIYUh6QzX4p0rMpCdzDmxghZLZk8dLuQh628', 'g_Ip_bkfpfT73USemt16PCyGcLKBkPmclVjsrKv51Po'),
|
'24595934-4540-4333-ac2b-78796ac3f25f', '5c5dfc88-83f1-4933-b5cc-4a48eb735bfd'),
|
||||||
('vs2C345OEZVqxxWxTAX5EfCjTxyM8cpp0993sP0vZ7M', 'wk2jFJku_7VvpM2hFIz2XBO0Yka9tLHwc6V0Yk8oYLA',
|
('6527c20f-f956-4c86-84c5-d2835813bd06', 'fe1b106c-18bc-4f85-943e-4950e0f3eb4f',
|
||||||
'60nc0XXDIYUh6QzX4p0rMpCdzDmxghZLZk8dLuQh628', 'X1j7UKLCwMTB3DbTuZvJxOBGoVDnApCjI894yAE7RFc');
|
'24595934-4540-4333-ac2b-78796ac3f25f', '87fdbcb7-1e87-4cbf-a792-5dfb13457423');
|
||||||
|
|
||||||
|
|
||||||
|
11
src/error.rs
11
src/error.rs
@ -172,3 +172,14 @@ impl From<tokio::sync::mpsc::error::SendError<Event>> for Error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<uuid::Error> for Error {
|
||||||
|
fn from(error: uuid::Error) -> Self {
|
||||||
|
Error {
|
||||||
|
kind: ErrorKind::UsimpError,
|
||||||
|
class: ErrorClass::ClientError,
|
||||||
|
msg: None,
|
||||||
|
desc: Some(error.to_string()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -5,6 +5,7 @@ use crate::websocket;
|
|||||||
use hyper::{body, header, Body, Method, Request, Response, StatusCode};
|
use hyper::{body, header, Body, Method, Request, Response, StatusCode};
|
||||||
use serde_json::{Map, Value};
|
use serde_json::{Map, Value};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
async fn endpoint_handler(
|
async fn endpoint_handler(
|
||||||
req: &mut Request<Body>,
|
req: &mut Request<Body>,
|
||||||
@ -63,12 +64,12 @@ async fn endpoint_handler(
|
|||||||
|
|
||||||
let input = InputEnvelope {
|
let input = InputEnvelope {
|
||||||
endpoint,
|
endpoint,
|
||||||
to_domain,
|
to_domain: Uuid::from_str(to_domain.as_str())?,
|
||||||
from_domain: match req
|
from_domain: match req
|
||||||
.headers()
|
.headers()
|
||||||
.get(header::HeaderName::from_str("From-Domain").unwrap())
|
.get(header::HeaderName::from_str("From-Domain").unwrap())
|
||||||
{
|
{
|
||||||
Some(val) => Some(val.to_str()?.to_string()),
|
Some(val) => Some(Uuid::from_str(val.to_str()?)?),
|
||||||
None => None,
|
None => None,
|
||||||
},
|
},
|
||||||
request_nr: None,
|
request_nr: None,
|
||||||
|
39
src/main.rs
39
src/main.rs
@ -10,6 +10,7 @@ use futures_util::{future::TryFutureExt, stream::Stream};
|
|||||||
use hyper::server::conn::AddrStream;
|
use hyper::server::conn::AddrStream;
|
||||||
use hyper::service::{make_service_fn, service_fn};
|
use hyper::service::{make_service_fn, service_fn};
|
||||||
use hyper::Server;
|
use hyper::Server;
|
||||||
|
use rustls_pemfile;
|
||||||
|
|
||||||
mod database;
|
mod database;
|
||||||
mod error;
|
mod error;
|
||||||
@ -47,8 +48,11 @@ fn load_certs(filename: &str) -> std::io::Result<Vec<rustls::Certificate>> {
|
|||||||
.map_err(|e| error(format!("failed to open {}: {}", filename, e)))?;
|
.map_err(|e| error(format!("failed to open {}: {}", filename, e)))?;
|
||||||
let mut reader = std::io::BufReader::new(certfile);
|
let mut reader = std::io::BufReader::new(certfile);
|
||||||
|
|
||||||
rustls::internal::pemfile::certs(&mut reader)
|
Ok(rustls_pemfile::certs(&mut reader)
|
||||||
.map_err(|_| error("failed to load certificate".into()))
|
.unwrap()
|
||||||
|
.iter()
|
||||||
|
.map(|v| rustls::Certificate(v.clone()))
|
||||||
|
.collect())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_private_key(filename: &str) -> std::io::Result<rustls::PrivateKey> {
|
fn load_private_key(filename: &str) -> std::io::Result<rustls::PrivateKey> {
|
||||||
@ -56,12 +60,17 @@ fn load_private_key(filename: &str) -> std::io::Result<rustls::PrivateKey> {
|
|||||||
.map_err(|e| error(format!("failed to open {}: {}", filename, e)))?;
|
.map_err(|e| error(format!("failed to open {}: {}", filename, e)))?;
|
||||||
let mut reader = std::io::BufReader::new(keyfile);
|
let mut reader = std::io::BufReader::new(keyfile);
|
||||||
|
|
||||||
let keys = rustls::internal::pemfile::rsa_private_keys(&mut reader)
|
loop {
|
||||||
.map_err(|_| error("failed to load private key".into()))?;
|
match rustls_pemfile::read_one(&mut reader).expect("cannot parse private key .pem file") {
|
||||||
if keys.len() < 1 {
|
Some(rustls_pemfile::Item::RSAKey(key)) => return Ok(rustls::PrivateKey(key)),
|
||||||
return Err(error("expected a single private key".into()));
|
Some(rustls_pemfile::Item::PKCS8Key(key)) => return Ok(rustls::PrivateKey(key)),
|
||||||
|
Some(rustls_pemfile::Item::ECKey(key)) => return Ok(rustls::PrivateKey(key)),
|
||||||
|
None => break,
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
Ok(keys[0].clone())
|
}
|
||||||
|
|
||||||
|
Err(error("unexpected error".into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn error(err: String) -> std::io::Error {
|
fn error(err: String) -> std::io::Error {
|
||||||
@ -85,11 +94,17 @@ async fn main() -> Result<(), Error> {
|
|||||||
let srv1 = server1.serve(service);
|
let srv1 = server1.serve(service);
|
||||||
|
|
||||||
let tls_cfg = {
|
let tls_cfg = {
|
||||||
let certs = load_certs("/home/lorenz/Certificates/priv/fullchain.pem").unwrap();
|
let certs = load_certs("/home/lorenz/Certificates/priv/necronda.net/fullchain.pem").unwrap();
|
||||||
let key = load_private_key("/home/lorenz/Certificates/priv/privkey.pem").unwrap();
|
let key = load_private_key("/home/lorenz/Certificates/priv/necronda.net/privkey.pem").unwrap();
|
||||||
let mut cfg = rustls::ServerConfig::new(rustls::NoClientAuth::new());
|
let mut cfg = rustls::ServerConfig::builder()
|
||||||
cfg.set_single_cert(certs, key).unwrap();
|
.with_safe_default_cipher_suites()
|
||||||
cfg.set_protocols(&[b"h2".to_vec(), b"http/1.1".to_vec()]);
|
.with_safe_default_kx_groups()
|
||||||
|
.with_protocol_versions(rustls::ALL_VERSIONS)
|
||||||
|
.unwrap()
|
||||||
|
.with_no_client_auth()
|
||||||
|
.with_single_cert(certs, key)
|
||||||
|
.unwrap();
|
||||||
|
cfg.alpn_protocols = vec![b"h2".to_vec(), b"http/1.1".to_vec()];
|
||||||
std::sync::Arc::new(cfg)
|
std::sync::Arc::new(cfg)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ use crate::usimp::*;
|
|||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::{from_value, to_value, Value};
|
use serde_json::{from_value, to_value, Value};
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone)]
|
#[derive(Serialize, Deserialize, Clone)]
|
||||||
struct Input {
|
struct Input {
|
||||||
@ -26,14 +27,14 @@ pub async fn handle(input: &InputEnvelope, session: Option<Session>) -> Result<V
|
|||||||
|
|
||||||
async fn authenticate(input: Input, _session: Option<Session>) -> Result<Output, Error> {
|
async fn authenticate(input: Input, _session: Option<Session>) -> Result<Output, Error> {
|
||||||
let backend = database::client().await?;
|
let backend = database::client().await?;
|
||||||
let token;
|
let token: String;
|
||||||
let session_id;
|
let session_id;
|
||||||
match backend {
|
match backend {
|
||||||
database::Client::Postgres(client) => {
|
database::Client::Postgres(client) => {
|
||||||
let res = client
|
let res = client
|
||||||
.query(
|
.query(
|
||||||
"SELECT account_id, domain_id \
|
"SELECT account_id, domain_id \
|
||||||
FROM accounts \
|
FROM account \
|
||||||
WHERE account_name = $1",
|
WHERE account_name = $1",
|
||||||
&[&input.name],
|
&[&input.name],
|
||||||
)
|
)
|
||||||
@ -46,8 +47,8 @@ async fn authenticate(input: Input, _session: Option<Session>) -> Result<Output,
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
let row = &res[0];
|
let row = &res[0];
|
||||||
let account_id: String = row.get(0);
|
let account_id: Uuid = row.get(0);
|
||||||
let domain_id: String = row.get(1);
|
let domain_id: Uuid = row.get(1);
|
||||||
|
|
||||||
// TODO password check
|
// TODO password check
|
||||||
if !input.password.eq("MichaelScott") {
|
if !input.password.eq("MichaelScott") {
|
||||||
@ -58,7 +59,7 @@ async fn authenticate(input: Input, _session: Option<Session>) -> Result<Output,
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
session_id = usimp::get_id(&[domain_id.as_str(), account_id.as_str()]);
|
session_id = Uuid::new_v4();
|
||||||
token = rand::thread_rng()
|
token = rand::thread_rng()
|
||||||
.sample_iter(&rand::distributions::Alphanumeric)
|
.sample_iter(&rand::distributions::Alphanumeric)
|
||||||
.take(256)
|
.take(256)
|
||||||
@ -67,14 +68,14 @@ async fn authenticate(input: Input, _session: Option<Session>) -> Result<Output,
|
|||||||
|
|
||||||
client
|
client
|
||||||
.execute(
|
.execute(
|
||||||
"INSERT INTO sessions (account_id, session_nr, session_id, session_token) \
|
"INSERT INTO session (account_id, session_nr, session_id, session_token) \
|
||||||
VALUES ($1, COALESCE((SELECT MAX(session_nr) + 1 \
|
VALUES ($1, COALESCE((SELECT MAX(session_nr) + 1 \
|
||||||
FROM sessions \
|
FROM session \
|
||||||
WHERE account_id = $1), 1), $2, $3);",
|
WHERE account_id = $1), 1), $2, $3);",
|
||||||
&[&account_id, &session_id, &token],
|
&[&account_id, &session_id, &token],
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(Output { session_id, token })
|
Ok(Output { session_id: session_id.to_string(), token })
|
||||||
}
|
}
|
||||||
|
@ -6,12 +6,14 @@ use serde_json::{from_value, to_value, Value};
|
|||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone)]
|
#[derive(Serialize, Deserialize, Clone)]
|
||||||
struct Input {
|
struct Input {
|
||||||
room_id: String,
|
room_id: Uuid,
|
||||||
events: Vec<Event>,
|
events: Vec<Event>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone)]
|
#[derive(Serialize, Deserialize, Clone)]
|
||||||
struct Output {}
|
struct Output {
|
||||||
|
events: Vec<Uuid>,
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn handle(input: &InputEnvelope, session: Option<Session>) -> Result<Value, Error> {
|
pub async fn handle(input: &InputEnvelope, session: Option<Session>) -> Result<Value, Error> {
|
||||||
Ok(to_value(
|
Ok(to_value(
|
||||||
@ -21,9 +23,13 @@ pub async fn handle(input: &InputEnvelope, session: Option<Session>) -> Result<V
|
|||||||
|
|
||||||
async fn new_event(input: Input, session: Option<Session>) -> Result<Output, Error> {
|
async fn new_event(input: Input, session: Option<Session>) -> Result<Output, Error> {
|
||||||
let _account = get_account(&session)?;
|
let _account = get_account(&session)?;
|
||||||
|
let mut uuids = vec![];
|
||||||
// TODO check permissions
|
// TODO check permissions
|
||||||
for event in input.events {
|
for mut event in input.events {
|
||||||
subscription::push(input.room_id.as_str(), event).await?;
|
let uuid = Uuid::new_v4();
|
||||||
|
event.id = Some(uuid);
|
||||||
|
uuids.push(uuid);
|
||||||
|
subscription::push(&input.room_id, event).await?;
|
||||||
}
|
}
|
||||||
Ok(Output {})
|
Ok(Output {events: uuids})
|
||||||
}
|
}
|
||||||
|
@ -10,12 +10,13 @@ use crypto::digest::Digest;
|
|||||||
use crypto::sha2::Sha256;
|
use crypto::sha2::Sha256;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct InputEnvelope {
|
pub struct InputEnvelope {
|
||||||
pub endpoint: String,
|
pub endpoint: String,
|
||||||
pub from_domain: Option<String>,
|
pub from_domain: Option<Uuid>,
|
||||||
pub to_domain: String,
|
pub to_domain: Uuid,
|
||||||
pub token: Option<String>,
|
pub token: Option<String>,
|
||||||
pub request_nr: Option<u64>,
|
pub request_nr: Option<u64>,
|
||||||
pub data: Value,
|
pub data: Value,
|
||||||
@ -30,32 +31,21 @@ pub struct OutputEnvelope {
|
|||||||
#[derive(Clone, Serialize, Deserialize)]
|
#[derive(Clone, Serialize, Deserialize)]
|
||||||
pub struct Event {
|
pub struct Event {
|
||||||
data: Value,
|
data: Value,
|
||||||
|
id: Option<Uuid>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Account {
|
pub struct Account {
|
||||||
id: String,
|
id: Uuid,
|
||||||
name: String,
|
name: String,
|
||||||
domain: String,
|
domain: Uuid,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Session {
|
pub struct Session {
|
||||||
id: String,
|
id: Uuid,
|
||||||
nr: i32,
|
nr: i32,
|
||||||
account: Option<Account>,
|
account: Option<Account>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_id(input: &[&str]) -> String {
|
|
||||||
let mut hasher = Sha256::new();
|
|
||||||
hasher.input_str(chrono::Utc::now().timestamp_millis().to_string().as_str());
|
|
||||||
for part in input {
|
|
||||||
hasher.input_str(" ");
|
|
||||||
hasher.input_str(part);
|
|
||||||
}
|
|
||||||
let mut result = [0u8; 32];
|
|
||||||
hasher.result(&mut result);
|
|
||||||
base64_url::encode(&result)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_account(session: &Option<Session>) -> Result<&Account, Error> {
|
pub fn get_account(session: &Option<Session>) -> Result<&Account, Error> {
|
||||||
match session {
|
match session {
|
||||||
Some(session) => match &session.account {
|
Some(session) => match &session.account {
|
||||||
@ -97,7 +87,7 @@ impl Session {
|
|||||||
let res = client
|
let res = client
|
||||||
.query(
|
.query(
|
||||||
"SELECT session_id, session_nr, a.account_id, account_name, domain_id \
|
"SELECT session_id, session_nr, a.account_id, account_name, domain_id \
|
||||||
FROM accounts a JOIN sessions s ON a.account_id = s.account_id \
|
FROM account a JOIN session s ON a.account_id = s.account_id \
|
||||||
WHERE session_token = $1;",
|
WHERE session_token = $1;",
|
||||||
&[&token],
|
&[&token],
|
||||||
)
|
)
|
||||||
|
@ -4,8 +4,8 @@ use std::collections::HashMap;
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tokio::sync::{mpsc, Mutex};
|
use tokio::sync::{mpsc, Mutex};
|
||||||
|
|
||||||
static mut ROOMS: Option<Arc<Mutex<HashMap<String, Vec<mpsc::Sender<Event>>>>>> = None;
|
static mut ROOMS: Option<Arc<Mutex<HashMap<Uuid, Vec<mpsc::Sender<Event>>>>>> = None;
|
||||||
static mut ACCOUNTS: Option<Arc<Mutex<HashMap<String, Vec<mpsc::Sender<Event>>>>>> = None;
|
static mut ACCOUNTS: Option<Arc<Mutex<HashMap<Uuid, Vec<mpsc::Sender<Event>>>>>> = None;
|
||||||
|
|
||||||
pub fn init() {
|
pub fn init() {
|
||||||
unsafe {
|
unsafe {
|
||||||
@ -18,31 +18,31 @@ pub async fn subscribe_account(account: &Account) -> mpsc::Receiver<Event> {
|
|||||||
let (tx, rx) = mpsc::channel::<Event>(64);
|
let (tx, rx) = mpsc::channel::<Event>(64);
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut acc = ACCOUNTS.as_ref().unwrap().lock().await;
|
let mut acc = ACCOUNTS.as_ref().unwrap().lock().await;
|
||||||
match acc.get_mut(account.id.as_str()) {
|
match acc.get_mut(&account.id) {
|
||||||
Some(vec) => {
|
Some(vec) => {
|
||||||
vec.push(tx);
|
vec.push(tx);
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
acc.insert(account.id.clone(), vec![tx]);
|
acc.insert(account.id, vec![tx]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rx
|
rx
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn push(room_id: &str, event: Event) -> Result<(), Error> {
|
pub async fn push(room_id: &Uuid, event: Event) -> Result<(), Error> {
|
||||||
let backend = database::client().await?;
|
let backend = database::client().await?;
|
||||||
let accounts = match backend {
|
let accounts = match backend {
|
||||||
database::Client::Postgres(client) => {
|
database::Client::Postgres(client) => {
|
||||||
let res = client
|
let res = client
|
||||||
.query(
|
.query(
|
||||||
"SELECT account_id \
|
"SELECT account_id \
|
||||||
FROM members \
|
FROM member \
|
||||||
WHERE room_id = $1;",
|
WHERE room_id = $1;",
|
||||||
&[&room_id],
|
&[&room_id],
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
let mut acc: Vec<String> = Vec::new();
|
let mut acc: Vec<Uuid> = Vec::new();
|
||||||
for row in res {
|
for row in res {
|
||||||
acc.push(row.get(0));
|
acc.push(row.get(0));
|
||||||
}
|
}
|
||||||
@ -62,7 +62,7 @@ pub async fn push(room_id: &str, event: Event) -> Result<(), Error> {
|
|||||||
for account in accounts {
|
for account in accounts {
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut accounts = ACCOUNTS.as_ref().unwrap().lock().await;
|
let mut accounts = ACCOUNTS.as_ref().unwrap().lock().await;
|
||||||
if let Some(acc) = accounts.get_mut(account.as_str()) {
|
if let Some(acc) = accounts.get_mut(&account) {
|
||||||
let mut acc = acc.clone();
|
let mut acc = acc.clone();
|
||||||
rooms.append(&mut acc);
|
rooms.append(&mut acc);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user