execute from local file if possible

master
Edward Shen 2019-12-31 19:12:17 -05:00
parent 1385045013
commit c990aef0e9
Signed by: edward
GPG Key ID: F350507060ED6C90
3 changed files with 46 additions and 19 deletions

View File

@ -6,5 +6,6 @@
"bunbunsearch",
"itertools",
"opensearchdescription"
]
],
"python.pythonPath": "/usr/bin/python3"
}

View File

@ -15,6 +15,17 @@ default_route: "g"
# contain "{{query}}", which will be populated by the user's search query. This
# input is percent-escaped. If multiple routes are defined, then the later
# defined route is used.
#
# You may provide an (absolute, recommended) path to an executable file to out-
# source route resolution to a program. The program will receive one argument
# only, which is the entire string provided from the user after matching the
# route. It is up to the out-sourced program to parse the arguments and to
# interpret those arguments. These programs should print one line to standard
# out, which should be a fully resolved URL to lead the user to.
#
# These programs must be developed defensively, as they accept arbitrary user
# input. Improper handling of user input can easily lead to anywhere from simple
# flakey responses to remote code execution.
groups:
-
name: "Meta commands"

View File

@ -6,11 +6,12 @@ use actix_web::web::{Data, Query};
use actix_web::{HttpRequest, HttpResponse, Responder};
use handlebars::Handlebars;
use itertools::Itertools;
use log::debug;
use log::{debug, error};
use percent_encoding::{utf8_percent_encode, AsciiSet, CONTROLS};
use serde::{de::Visitor, Deserialize, Deserializer, Serialize, Serializer};
use std::collections::HashMap;
use std::fmt;
use std::process::Command;
use std::sync::{Arc, RwLock};
/// https://url.spec.whatwg.org/#fragment-percent-encode-set
@ -112,24 +113,34 @@ pub async fn hop(
let data = data.read().unwrap();
match resolve_hop(&query.to, &data.routes, &data.default_route) {
(Some(path), args) => HttpResponse::Found()
.header(
header::LOCATION,
req
.app_data::<Handlebars>()
.unwrap()
.render_template(
match path {
Route::Path(s) => s, // TODO: try resolve path
Route::External(s) => s,
},
&template_args::query(
utf8_percent_encode(&args, FRAGMENT_ENCODE_SET).to_string(),
),
(Some(path), args) => {
let resolved_template = match path {
Route::Path(path) => resolve_path(path, &args),
Route::External(path) => Ok(path.to_owned().into_bytes()),
};
match resolved_template {
Ok(path) => HttpResponse::Found()
.header(
header::LOCATION,
req
.app_data::<Handlebars>()
.unwrap()
.render_template(
&std::str::from_utf8(&path).unwrap().trim(),
&template_args::query(
utf8_percent_encode(&args, FRAGMENT_ENCODE_SET).to_string(),
),
)
.unwrap(),
)
.unwrap(),
)
.finish(),
.finish(),
Err(e) => {
error!("Failed to resolve template for path {}: {}", path, e);
HttpResponse::InternalServerError().body("Something went wrong :(")
}
}
}
(None, _) => HttpResponse::NotFound().body("not found"),
}
}
@ -203,6 +214,10 @@ pub async fn index(data: StateData, req: HttpRequest) -> impl Responder {
)
}
fn resolve_path(path: &str, args: &str) -> Result<Vec<u8>, crate::BunBunError> {
Ok(Command::new(path).arg(args).output()?.stdout)
}
#[get("/bunbunsearch.xml")]
pub async fn opensearch(data: StateData, req: HttpRequest) -> impl Responder {
let data = data.read().unwrap();