🚧 one-click server registration
parent
dc53aeed30
commit
a4ec4878ea
|
@ -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",
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
Loading…
Reference in New Issue