- main
- manifest
- deps
- main
- Install
- Run
use base64::engine::{general_purpose::STANDARD, Engine as _};
use fastly::http::{header, StatusCode};
use fastly::{mime, ConfigStore, Error, Request, Response};
use lazy_static::lazy_static;
use regex::Regex;
#[fastly::main]
fn main(mut req: Request) -> Result<Response, Error> {
let username_password = ConfigStore::open("username_password");
if let Some(credential) = req
.get_header(header::AUTHORIZATION)
.and_then(|header| header.to_str().ok())
.and_then(get_credential)
.filter(|credential| username_password.contains(credential))
{
let bytes = STANDARD.decode(credential)?;
let decoded = std::str::from_utf8(&bytes)?;
let username = get_username(decoded).unwrap();
req.remove_header(header::AUTHORIZATION);
req.set_header("authorized-user", &username);
println!("Access granted for user {}", username);
return Ok(req.send("origin_0")?);
}
let body = r#"
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Error</title>
<meta HTTP-EQUIV='Content-Type' CONTENT='text/html;'>
</head>
<body><h1>401 Unauthorized (Fastly)</h1></body>
</html>"#;
Ok(Response::from_body(body)
.with_status(StatusCode::UNAUTHORIZED)
.with_content_type(mime::TEXT_HTML_UTF_8)
.with_header(header::WWW_AUTHENTICATE, "Basic realm=MYREALM"))
}
fn get_credential(input: &str) -> Option<String> {
lazy_static! {
static ref RE: Regex = Regex::new(r"Basic (?P<credential>.*)$").unwrap();
}
RE.captures(input).and_then(|cap| {
cap.name("credential")
.map(|credential| credential.as_str().to_owned())
})
}
fn get_username(input: &str) -> Option<String> {
lazy_static! {
static ref RE: Regex = Regex::new(r"^(?P<username>.+?):.*$").unwrap();
}
RE.captures(input).and_then(|cap| {
cap.name("username")
.map(|username| username.as_str().to_owned())
})
}