one-click registration works

main
_ 2021-05-02 22:23:12 +00:00
parent ebd1026903
commit ce82f7d6a3
4 changed files with 72 additions and 68 deletions

View File

@ -123,12 +123,9 @@ async fn handle_http_request (
let req_method = req.method.clone (); let req_method = req.method.clone ();
{ if ! state.server_exists (server_name).await {
let config = state.config.read ().await;
if ! config.servers.contains_key (server_name) {
return Err (UnknownServer); return Err (UnknownServer);
} }
}
let user = get_user_name (&req); let user = get_user_name (&req);
@ -643,10 +640,16 @@ async fn handle_all (
let api_key = req.headers ().get ("X-ApiKey"); let api_key = req.headers ().get ("X-ApiKey");
let api_key = match api_key { let api_key = match api_key {
None => return Ok (error_reply (StatusCode::FORBIDDEN, "Can't run server without an API key")?), None => return Ok (error_reply (StatusCode::FORBIDDEN, "Forbidden")?),
Some (x) => x, Some (x) => x,
}; };
server_endpoint::handle_listen (state, listen_code.into (), api_key.as_bytes ()).await?
match check_server_api_key (state, listen_code, api_key.as_bytes ()).await {
Ok (_) => (),
Err (_) => return Ok (error_reply (StatusCode::FORBIDDEN, "Forbidden")?)
}
server_endpoint::handle_listen (state, listen_code.into ()).await?
}, },
ServerHttpResponse { ServerHttpResponse {
request_code, request_code,
@ -658,41 +661,42 @@ async fn handle_all (
Ok (response) Ok (response)
} }
async fn check_server_api_key (state: &Relay, name: &str, req: &http::request::Parts) async fn check_server_api_key (state: &Relay, name: &str, api_key: &[u8])
-> Result <(), anyhow::Error> -> Result <(), anyhow::Error>
{ {
let api_key = req.headers.get ("X-ApiKey"); let actual_tripcode = key_validity::BlakeHashWrapper::from_key (api_key);
let api_key = match api_key { let expected_human = {
None => bail! ("Can't run server without an API key"),
Some (x) => x,
};
let actual_tripcode = blake3::hash (api_key.as_bytes ());
let expected_tripcode = {
let config = state.config.read ().await; let config = state.config.read ().await;
match config.servers.get (name) { config.servers.get (name).map (|s| s.tripcode.clone ())
None => { };
let expected_machine = {
let me_config = state.me_config.read ().await;
me_config.servers.get (name).map (|s| s.tripcode.clone ())
};
if expected_machine.is_none () && expected_human.is_none () {
state.unregistered_servers.push (crate::RejectedServer { state.unregistered_servers.push (crate::RejectedServer {
name: name.to_string (), name: name.to_string (),
tripcode: actual_tripcode, tripcode: *actual_tripcode,
seen: Utc::now (), seen: Utc::now (),
}).await; }).await;
bail! ("Denied API request for non-existent server name {}", name); bail! ("Denied API request for non-existent server name {}", name);
},
Some (x) => *(*x).tripcode,
} }
};
if expected_tripcode != actual_tripcode { if Some (actual_tripcode) == expected_human {
return Ok (());
}
if Some (actual_tripcode) == expected_machine {
return Ok (());
}
bail! ("Denied API request for bad tripcode {}", base64::encode (actual_tripcode.as_bytes ())); bail! ("Denied API request for bad tripcode {}", base64::encode (actual_tripcode.as_bytes ()));
} }
Ok (())
}
fn load_templates (asset_root: &Path) fn load_templates (asset_root: &Path)
-> Result <Handlebars <'static>, RelayError> -> Result <Handlebars <'static>, RelayError>
{ {

View File

@ -182,7 +182,7 @@ impl TryFrom <Config> for Relay {
let me_config = match machine_editable::Config::from_file (Path::new ("data/ptth_relay_me_config.toml")) let me_config = match machine_editable::Config::from_file (Path::new ("data/ptth_relay_me_config.toml"))
{ {
Err (e) => { Err (e) => {
error! ("Can't load machine-editable config: {:?}", e); warn! ("Can't load machine-editable config: {:?}", e);
me_config me_config
}, },
Ok (x) => x, Ok (x) => x,
@ -211,6 +211,24 @@ impl Relay {
.collect () .collect ()
} }
pub async fn server_exists (&self, name: &str) -> bool {
{
let config = self.config.read ().await;
if config.servers.contains_key (name) {
return true;
}
}
{
let config = self.me_config.read ().await;
if config.servers.contains_key (name) {
return true;
}
}
false
}
pub fn build () -> Builder { pub fn build () -> Builder {
Builder::default () Builder::default ()
} }

View File

@ -68,20 +68,31 @@ pub async fn v1_server_list (state: &Relay)
-> ServerList -> ServerList
{ {
// name --> display_name // name --> display_name
let display_names: HashMap <String, String> = { let mut display_names = HashMap::new ();
{
let guard = state.config.read ().await; let guard = state.config.read ().await;
let servers = (*guard).servers.iter () for (k, v) in &guard.servers {
.map (|(k, v)| {
let display_name = v.display_name let display_name = v.display_name
.clone () .clone ()
.unwrap_or_else (|| k.clone ()); .unwrap_or_else (|| k.clone ());
(k.clone (), display_name) display_names.insert (k.clone (), display_name);
}); }
}
servers.collect () {
}; let guard = state.me_config.read ().await;
for (k, v) in &guard.servers {
let display_name = v.display_name
.clone ()
.unwrap_or_else (|| k.clone ());
display_names.insert (k.clone (), display_name);
}
}
// name --> status // name --> status
let server_statuses = { let server_statuses = {

View File

@ -45,41 +45,12 @@ use super::{
pub async fn handle_listen ( pub async fn handle_listen (
state: &Relay, state: &Relay,
watcher_code: String, watcher_code: String,
api_key: &[u8],
) )
-> Result <Response <Body>, RequestError> -> Result <Response <Body>, RequestError>
{ {
use super::RequestRendezvous::*; use super::RequestRendezvous::*;
let trip_error = || Ok (error_reply (StatusCode::UNAUTHORIZED, "Bad X-ApiKey")?);
let now = Utc::now (); let now = Utc::now ();
let actual_tripcode = blake3::hash (api_key);
let expected_tripcode = {
let config = state.config.read ().await;
match config.servers.get (&watcher_code) {
None => {
error! ("Denied http_listen for non-existent server name {}", watcher_code);
state.unregistered_servers.push (crate::RejectedServer {
name: watcher_code,
tripcode: actual_tripcode,
seen: now,
}).await;
return trip_error ();
},
Some (x) => *(*x).tripcode,
}
};
if expected_tripcode != actual_tripcode {
error! ("Denied http_listen for bad tripcode {}", base64::encode (actual_tripcode.as_bytes ()));
return trip_error ();
}
// End of early returns
{ {
// TODO: Move into relay_state.rs // TODO: Move into relay_state.rs