🚧 one-click server registration

main
_ 2021-05-02 21:18:07 +00:00
parent dc53aeed30
commit a4ec4878ea
6 changed files with 83 additions and 12 deletions

2
Cargo.lock generated
View File

@ -1545,6 +1545,7 @@ dependencies = [
name = "ptth_relay"
version = "2.0.0"
dependencies = [
"anyhow",
"base64",
"blake3",
"chrono",
@ -1562,6 +1563,7 @@ dependencies = [
"rusty_ulid",
"serde",
"serde_json",
"serde_urlencoded",
"thiserror",
"tokio",
"tokio-stream",

View File

@ -11,6 +11,7 @@ repository = "https://github.com/ReactorScram/ptth"
[dependencies]
anyhow = "1.0.38"
base64 = "0.13.0"
blake3 = "0.3.7"
chrono = { version = "0.4.19", features = ["serde"] }
@ -27,6 +28,7 @@ rmp-serde = "0.14.4"
rusty_ulid = "0.10.1"
serde = { version = "1.0.117", features = ["derive"] }
serde_json = "1.0.60"
serde_urlencoded = "0.7.0"
thiserror = "1.0.22"
tokio = { version = "1.4.0", features = [] }
tokio-stream = "0.1.3"

View File

@ -22,7 +22,6 @@
use std::{
borrow::Cow,
collections::HashSet,
convert::Infallible,
net::SocketAddr,
path::{Path, PathBuf},
@ -30,6 +29,7 @@ use std::{
time::Duration,
};
use anyhow::bail;
use chrono::{
DateTime,
SecondsFormat,
@ -77,6 +77,10 @@ pub use config::{
};
pub use errors::*;
pub use relay_state::Relay;
use relay_state::{
AuditData,
AuditEvent,
};
use relay_state::{
RejectedServer,
@ -98,6 +102,12 @@ fn error_reply (status: StatusCode, b: &str)
.body (format! ("{}\n", b).into ())
}
fn get_user_name (req: &http::request::Parts)
-> Option <String>
{
req.headers.get ("X-Email").map (|x| Some (x.to_str ().ok ()?.to_string ())).flatten ()
}
/// Clients will come here to start requests, and always park for at least
/// a short amount of time.
@ -109,10 +119,6 @@ async fn handle_http_request (
)
-> Result <Response <Body>, RequestError>
{
use crate::relay_state::{
AuditData,
AuditEvent,
};
use RequestError::*;
let req_method = req.method.clone ();
@ -124,7 +130,7 @@ async fn handle_http_request (
}
}
let user = req.headers.get ("X-Email").map (|x| Some (x.to_str ().ok ()?.to_string ())).flatten ();
let user = get_user_name (&req);
let req = match http_serde::RequestParts::from_hyper (req.method, uri.clone (), req.headers) {
Ok (x) => x,
@ -522,6 +528,45 @@ async fn handle_gen_scraper_key (_state: Arc <Relay>)
.body (Body::from (body))
}
async fn handle_register_server (req: Request <Body>, state: Arc <Relay>)
-> Result <(), anyhow::Error>
{
let (parts, body) = req.into_parts ();
let user = get_user_name (&parts);
let form_data = read_body_limited (body, 1_024).await?;
let reg: relay_state::Registration = serde_urlencoded::from_bytes (&form_data)?;
state.audit_log.push (AuditEvent::new (AuditData::RegisterServer {
user,
reg: reg.clone (),
})).await;
{
let mut me_config = state.me_config.write ().await;
//me_config.servers.
}
Ok (())
}
async fn read_body_limited (mut body: Body, limit: usize) -> anyhow::Result <Vec <u8>>
{
let mut buffer = vec! [];
while let Some (chunk) = body.next ().await {
let chunk = chunk?;
if buffer.len () + chunk.len () > limit {
bail! ("Body was bigger than limit");
}
buffer.extend_from_slice (&chunk);
}
Ok (buffer)
}
#[instrument (level = "trace", skip (req, state, handlebars))]
async fn handle_all (
req: Request <Body>,
@ -589,6 +634,15 @@ async fn handle_all (
},
ErrorMethodNotAllowed => error_reply (StatusCode::METHOD_NOT_ALLOWED, "Method not allowed. Are you POST-ing to a GET-only url, or vice versa?")?,
ErrorRoutingFailed => error_reply (StatusCode::OK, "URL routing failed")?,
RegisterServer => {
match handle_register_server (req, state).await {
Ok (_) => Response::builder ()
.status (StatusCode::TEMPORARY_REDIRECT)
.header ("location", "unregistered_servers")
.body (Body::from ("Success. Redirecting..."))?,
Err (e) => error_reply (StatusCode::BAD_REQUEST, &format! ("{:?}", e))?,
}
}
Root => {
let s = handlebars.render ("root", &())?;
ok_reply (s)?
@ -675,11 +729,6 @@ pub async fn run_relay (
)
-> Result <(), RelayError>
{
use crate::relay_state::{
AuditData,
AuditEvent,
};
let handlebars = Arc::new (load_templates (asset_root)?);
if let Some (x) = git_version::read ().await {

View File

@ -7,6 +7,7 @@ use std::{
use chrono::{DateTime, Utc};
use dashmap::DashMap;
use serde::Deserialize;
use tokio::sync::{
Mutex,
RwLock,
@ -116,6 +117,10 @@ pub struct AuditEvent {
#[derive (Clone, Debug)]
pub enum AuditData {
RegisterServer {
user: Option <String>,
reg: Registration,
},
RelayStart,
WebClientGet {
user: Option <String>,
@ -125,6 +130,12 @@ pub enum AuditData {
},
}
#[derive (Clone, Debug, Deserialize)]
pub struct Registration {
name: String,
tripcode: String,
}
impl AuditEvent {
pub fn new (data: AuditData) -> Self {
Self {

View File

@ -20,6 +20,7 @@ pub enum Route <'a> {
ErrorCantPost,
ErrorMethodNotAllowed,
ErrorRoutingFailed,
RegisterServer,
Root,
Scraper {
rest: &'a str,
@ -45,6 +46,9 @@ pub fn route_url <'a> (method: &Method, path: &'a str) -> Route <'a> {
else if path == "/frontend/debug/toggle" {
Route::DebugToggle
}
else if path == "/frontend/register" {
Route::RegisterServer
}
else {
Route::ErrorCantPost
}

View File

@ -29,6 +29,7 @@ AIABAACAAQAAgAEAAIABAACAAQAAgAEAAIABAACAAQAA" rel="icon" type="image/x-icon" />
border-collapse: collapse;
}
.padded {
display: block;
padding: 20px;
}
.submit {
@ -61,11 +62,13 @@ AIABAACAAQAAgAEAAIABAACAAQAAgAEAAIABAACAAQAA" rel="icon" type="image/x-icon" />
<td><span class="padded">{{this.name}}</span></td>
<td>
<span class="padded">{{this.tripcode}}</span>
<form>
<!--
<form action="register" method="post">
<input type="hidden" name="name" value="{{this.name}}">
<input type="hidden" name="tripcode" value="{{this.tripcode}}">
<input class="submit" type="submit" value="Register">
</form>
-->
</td>
<td><span class="padded">{{this.last_seen}}</span></td>
</tr>