execute from local file if possible

This commit is contained in:
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", "bunbunsearch",
"itertools", "itertools",
"opensearchdescription" "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 # 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 # input is percent-escaped. If multiple routes are defined, then the later
# defined route is used. # 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: groups:
- -
name: "Meta commands" name: "Meta commands"

View file

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