[WIP] authenticate working

This commit is contained in:
2021-05-22 20:24:44 +02:00
parent faa8c8e0a5
commit baec902243
7 changed files with 144 additions and 9 deletions

View File

@ -18,3 +18,4 @@ r2d2_postgres = "0.18.0"
ansi_term = "0.12"
rust-crypto = "^0.2"
base64 = "0.13.0"
base64-url = "1.4.10"

View File

@ -17,7 +17,7 @@ static mut POOL: Option<Arc<Mutex<Pool>>> = None;
pub fn init() -> Result<(), Error> {
let manager = PostgresConnectionManager::new(
"host=localhost user=postgres dbname=test".parse().unwrap(),
"host=localhost user=postgres dbname=locutus".parse().unwrap(),
NoTls,
);

View File

@ -12,6 +12,7 @@ pub enum Kind {
NotImplementedError,
UsimpProtocolError,
Utf8DecodeError,
AuthenticationError,
}
#[derive(Copy, Clone, Debug)]
@ -61,6 +62,7 @@ impl Error {
Kind::NotImplementedError => "Not yet implemented",
Kind::UsimpProtocolError => "USIMP protocol error",
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::UsimpProtocolError => "usimp protocol error",
Kind::Utf8DecodeError => "unable to decode utf-8 data",
Kind::AuthenticationError => "unable to authenticate",
}
.to_string();
if let Some(desc) = &self.desc {

View File

@ -3,6 +3,7 @@ use crate::error::*;
use crate::usimp;
use crate::websocket;
use serde_json;
use crate::usimp::Envelope;
pub fn connection_handler(client: super::Stream) {
let mut client = super::HttpStream {
@ -49,6 +50,8 @@ fn request_handler(client: &mut super::HttpStream) {
return websocket::connection_handler(client, &req, res);
}
// TODO check Content-Type == application/json
let mut error = None;
let parts: Vec<&str> = req.uri.split('/').collect();
@ -167,12 +170,48 @@ fn endpoint_handler(
client.stream.read_exact(&mut buf[..length]).unwrap();
// TODO decompress
let input = match serde_json::from_slice(&buf[..length]) {
let data = match serde_json::from_slice(&buf[..length]) {
Ok(val) => val,
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",
Err(e) => return error_handler(client, res, e),
};

View File

@ -266,7 +266,7 @@ impl Response {
buf = Some(new_buf);
}
self.send(stream);
self.send(stream)?;
if let Some(buf) = buf {
stream.write_all(buf.as_bytes())?;

View File

@ -3,14 +3,38 @@ use serde_json;
use crate::database;
use crate::error::*;
use crypto::digest::Digest;
pub fn endpoint(endpoint: &str, input: serde_json::Value) -> Result<serde_json::Value, Error> {
match endpoint {
"echo" => Ok(serde_json::to_value(echo(serde_json::from_value(input)?)?)?),
_ => Err(Error::new(Kind::InvalidEndpointError, Class::ClientError)),
pub struct Envelope {
pub endpoint: String,
pub from_domain: String,
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)]
pub struct EchoInput {
message: String,
@ -38,3 +62,71 @@ pub fn echo(input: EchoInput) -> Result<EchoOutput, Error> {
}
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 {})
}

View File

@ -180,7 +180,7 @@ pub fn connection_handler(
// TODO threads?
let req: RequestEnvelope = serde_json::from_str(msg.data.as_str()).unwrap();
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) => {
println!("Received close frame: {}: {}", msg.code.unwrap_or(0), msg.reason.unwrap_or("-".to_string()));