[WIP] authenticate working
This commit is contained in:
@ -18,3 +18,4 @@ r2d2_postgres = "0.18.0"
|
|||||||
ansi_term = "0.12"
|
ansi_term = "0.12"
|
||||||
rust-crypto = "^0.2"
|
rust-crypto = "^0.2"
|
||||||
base64 = "0.13.0"
|
base64 = "0.13.0"
|
||||||
|
base64-url = "1.4.10"
|
||||||
|
@ -17,7 +17,7 @@ static mut POOL: Option<Arc<Mutex<Pool>>> = None;
|
|||||||
|
|
||||||
pub fn init() -> Result<(), Error> {
|
pub fn init() -> Result<(), Error> {
|
||||||
let manager = PostgresConnectionManager::new(
|
let manager = PostgresConnectionManager::new(
|
||||||
"host=localhost user=postgres dbname=test".parse().unwrap(),
|
"host=localhost user=postgres dbname=locutus".parse().unwrap(),
|
||||||
NoTls,
|
NoTls,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@ pub enum Kind {
|
|||||||
NotImplementedError,
|
NotImplementedError,
|
||||||
UsimpProtocolError,
|
UsimpProtocolError,
|
||||||
Utf8DecodeError,
|
Utf8DecodeError,
|
||||||
|
AuthenticationError,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
@ -61,6 +62,7 @@ impl Error {
|
|||||||
Kind::NotImplementedError => "Not yet implemented",
|
Kind::NotImplementedError => "Not yet implemented",
|
||||||
Kind::UsimpProtocolError => "USIMP protocol error",
|
Kind::UsimpProtocolError => "USIMP protocol error",
|
||||||
Kind::Utf8DecodeError => "Unable to decode UTF-8 data",
|
Kind::Utf8DecodeError => "Unable to decode UTF-8 data",
|
||||||
|
Kind::AuthenticationError => "Unable to authenticate",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -91,6 +93,7 @@ impl fmt::Display for Error {
|
|||||||
Kind::NotImplementedError => "not yet implemented",
|
Kind::NotImplementedError => "not yet implemented",
|
||||||
Kind::UsimpProtocolError => "usimp protocol error",
|
Kind::UsimpProtocolError => "usimp protocol error",
|
||||||
Kind::Utf8DecodeError => "unable to decode utf-8 data",
|
Kind::Utf8DecodeError => "unable to decode utf-8 data",
|
||||||
|
Kind::AuthenticationError => "unable to authenticate",
|
||||||
}
|
}
|
||||||
.to_string();
|
.to_string();
|
||||||
if let Some(desc) = &self.desc {
|
if let Some(desc) = &self.desc {
|
||||||
|
@ -3,6 +3,7 @@ use crate::error::*;
|
|||||||
use crate::usimp;
|
use crate::usimp;
|
||||||
use crate::websocket;
|
use crate::websocket;
|
||||||
use serde_json;
|
use serde_json;
|
||||||
|
use crate::usimp::Envelope;
|
||||||
|
|
||||||
pub fn connection_handler(client: super::Stream) {
|
pub fn connection_handler(client: super::Stream) {
|
||||||
let mut client = super::HttpStream {
|
let mut client = super::HttpStream {
|
||||||
@ -49,6 +50,8 @@ fn request_handler(client: &mut super::HttpStream) {
|
|||||||
return websocket::connection_handler(client, &req, res);
|
return websocket::connection_handler(client, &req, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO check Content-Type == application/json
|
||||||
|
|
||||||
let mut error = None;
|
let mut error = None;
|
||||||
let parts: Vec<&str> = req.uri.split('/').collect();
|
let parts: Vec<&str> = req.uri.split('/').collect();
|
||||||
|
|
||||||
@ -167,12 +170,48 @@ fn endpoint_handler(
|
|||||||
client.stream.read_exact(&mut buf[..length]).unwrap();
|
client.stream.read_exact(&mut buf[..length]).unwrap();
|
||||||
|
|
||||||
// TODO decompress
|
// TODO decompress
|
||||||
let input = match serde_json::from_slice(&buf[..length]) {
|
let data = match serde_json::from_slice(&buf[..length]) {
|
||||||
Ok(val) => val,
|
Ok(val) => val,
|
||||||
Err(e) => return error_handler(client, res, e.into()),
|
Err(e) => return error_handler(client, res, e.into()),
|
||||||
};
|
};
|
||||||
|
|
||||||
let buf = match usimp::endpoint(endpoint, input) {
|
let mut authorization = None;
|
||||||
|
if let Some(auth) = req.header.find_field("Authorization") {
|
||||||
|
authorization = Some(auth.split(" ").skip(1).collect());
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut from_domain;
|
||||||
|
if let Some(from) = req.header.find_field("From-Domain") {
|
||||||
|
from_domain = from.to_string();
|
||||||
|
} else {
|
||||||
|
return error_handler(
|
||||||
|
client,
|
||||||
|
res,
|
||||||
|
Error::new(Kind::UsimpProtocolError, Class::ClientError)
|
||||||
|
.set_desc("Unable to find field 'From-Domain'".to_string())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut to_domain;
|
||||||
|
if let Some(to) = req.header.find_field("To-Domain") {
|
||||||
|
to_domain = to.to_string();
|
||||||
|
} else {
|
||||||
|
return error_handler(
|
||||||
|
client,
|
||||||
|
res,
|
||||||
|
Error::new(Kind::UsimpProtocolError, Class::ClientError)
|
||||||
|
.set_desc("Unable to find field 'To-Domain'".to_string())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let input = Envelope {
|
||||||
|
endpoint: endpoint.to_string(),
|
||||||
|
from_domain,
|
||||||
|
to_domain,
|
||||||
|
authorization,
|
||||||
|
data,
|
||||||
|
};
|
||||||
|
let buf = match usimp::endpoint(input) {
|
||||||
Ok(output) => output.to_string() + "\r\n",
|
Ok(output) => output.to_string() + "\r\n",
|
||||||
Err(e) => return error_handler(client, res, e),
|
Err(e) => return error_handler(client, res, e),
|
||||||
};
|
};
|
||||||
|
@ -266,7 +266,7 @@ impl Response {
|
|||||||
buf = Some(new_buf);
|
buf = Some(new_buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.send(stream);
|
self.send(stream)?;
|
||||||
|
|
||||||
if let Some(buf) = buf {
|
if let Some(buf) = buf {
|
||||||
stream.write_all(buf.as_bytes())?;
|
stream.write_all(buf.as_bytes())?;
|
||||||
|
100
src/usimp/mod.rs
100
src/usimp/mod.rs
@ -3,12 +3,36 @@ use serde_json;
|
|||||||
|
|
||||||
use crate::database;
|
use crate::database;
|
||||||
use crate::error::*;
|
use crate::error::*;
|
||||||
|
use crypto::digest::Digest;
|
||||||
|
|
||||||
pub fn endpoint(endpoint: &str, input: serde_json::Value) -> Result<serde_json::Value, Error> {
|
pub struct Envelope {
|
||||||
match endpoint {
|
pub endpoint: String,
|
||||||
"echo" => Ok(serde_json::to_value(echo(serde_json::from_value(input)?)?)?),
|
pub from_domain: String,
|
||||||
_ => Err(Error::new(Kind::InvalidEndpointError, Class::ClientError)),
|
pub to_domain: String,
|
||||||
|
pub authorization: Option<String>,
|
||||||
|
pub data: serde_json::Value,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn endpoint(envelope: Envelope) -> Result<serde_json::Value, Error> {
|
||||||
|
// TODO check authorization
|
||||||
|
// TODO domain_check
|
||||||
|
match envelope.endpoint.as_str() {
|
||||||
|
"echo" => Ok(serde_json::to_value(echo(serde_json::from_value(envelope.data)?)?)?),
|
||||||
|
"authorize" => Ok(serde_json::to_value(authorize(serde_json::from_value(envelope.data)?)?)?),
|
||||||
|
"notify" => Ok(serde_json::to_value(notify(serde_json::from_value(envelope.data)?)?)?),
|
||||||
|
_ => return Err(Error::new(Kind::InvalidEndpointError, Class::ClientError)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_id(input: &str) -> String {
|
||||||
|
let mut hasher = crypto::sha2::Sha256::new();
|
||||||
|
hasher.input_str(chrono::Utc::now().timestamp_millis().to_string().as_str());
|
||||||
|
hasher.input_str(" ");
|
||||||
|
hasher.input_str(input);
|
||||||
|
|
||||||
|
let mut result = [0u8; 32];
|
||||||
|
hasher.result(&mut result);
|
||||||
|
base64_url::encode(&result)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
@ -38,3 +62,71 @@ pub fn echo(input: EchoInput) -> Result<EchoOutput, Error> {
|
|||||||
}
|
}
|
||||||
Ok(output)
|
Ok(output)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
pub struct AuthorizeInput {
|
||||||
|
r#type: String,
|
||||||
|
name: String,
|
||||||
|
password: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
pub struct AuthorizeOutput {
|
||||||
|
token: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn authorize(input: AuthorizeInput) -> Result<AuthorizeOutput, Error> {
|
||||||
|
let backend = database::client()?;
|
||||||
|
|
||||||
|
let mut token;
|
||||||
|
match backend {
|
||||||
|
database::Client::Postgres(mut client) => {
|
||||||
|
let res = client.query("SELECT account_id FROM accounts WHERE name = $1", &[&input.name])?;
|
||||||
|
if res.len() == 0 {
|
||||||
|
return Err(Error::new(Kind::AuthenticationError, Class::ClientError));
|
||||||
|
}
|
||||||
|
token = res.get(0).unwrap().get(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(AuthorizeOutput { token })
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
pub struct SendEventInput {
|
||||||
|
room_id: String,
|
||||||
|
data: serde_json::Value,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
pub struct SendEventOutput {
|
||||||
|
event_id: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn send_event(input: SendEventInput) -> Result<SendEventOutput, Error> {
|
||||||
|
let backend = database::client()?;
|
||||||
|
let event_id = get_id("hermann"); // TODO fix id generation
|
||||||
|
let data = serde_json::to_string(&input.data)?;
|
||||||
|
|
||||||
|
match backend {
|
||||||
|
database::Client::Postgres(mut client) => {
|
||||||
|
client.execute("INSERT INTO events (event_id, room_id, data) VALUES ($1, $2, $3)", &[&event_id, &input.room_id, &data])?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(SendEventOutput { event_id })
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
pub struct NotifyInput {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
pub struct NotifyOutput {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn notify(input: NotifyInput) -> Result<NotifyOutput, Error> {
|
||||||
|
Ok(NotifyOutput {})
|
||||||
|
}
|
||||||
|
@ -180,7 +180,7 @@ pub fn connection_handler(
|
|||||||
// TODO threads?
|
// TODO threads?
|
||||||
let req: RequestEnvelope = serde_json::from_str(msg.data.as_str()).unwrap();
|
let req: RequestEnvelope = serde_json::from_str(msg.data.as_str()).unwrap();
|
||||||
println!("Endpoint: {}, ReqNo: {}, Data: {}", req.endpoint, req.request_nr, req.data);
|
println!("Endpoint: {}, ReqNo: {}, Data: {}", req.endpoint, req.request_nr, req.data);
|
||||||
let a = usimp::endpoint(req.endpoint.as_str(), req.data).unwrap();
|
//let a = usimp::endpoint(req.endpoint.as_str(), req.data).unwrap();
|
||||||
},
|
},
|
||||||
Message::CloseMessage(msg) => {
|
Message::CloseMessage(msg) => {
|
||||||
println!("Received close frame: {}: {}", msg.code.unwrap_or(0), msg.reason.unwrap_or("-".to_string()));
|
println!("Received close frame: {}: {}", msg.code.unwrap_or(0), msg.reason.unwrap_or("-".to_string()));
|
||||||
|
Reference in New Issue
Block a user