Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@mjg123
Created August 18, 2020 18:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mjg123/4d8657750f77ed21ef6060bc3b580ce1 to your computer and use it in GitHub Desktop.
Save mjg123/4d8657750f77ed21ef6060bc3b580ce1 to your computer and use it in GitHub Desktop.
import com.twilio.security.RequestValidator;
import java.util.HashMap;
import static spark.Spark.get;
import static spark.Spark.post;
public class RequestValidation {
public static void main(String[] args) {
setupUnvalidatedEndpoints();
setupValidatedEndpoints();
}
private static void setupUnvalidatedEndpoints() {
get("/unvalidated", (req, res) -> {
return "ok";
});
post("/unvalidated", (req, res) -> {
return "ok";
});
}
private static void setupValidatedEndpoints() {
var twilioAuthToken = System.getenv("TWILIO_AUTH_TOKEN");
var requestValidator = new RequestValidator(twilioAuthToken);
// We can't pull this from request.getUrl() because any proxy or API-gateway could
// have rewritten it by the time the request reaches our server, so hard-code
// the value from the Phone Number configuration page.
// (Note: it may be possible to reconstruct this from the headers as a proxy
// might put the original URL in a header, that depends on the proxy so this
// is simpler)
String webhookUrl = "https://d8f14df9f940.ngrok.io/validated";
get("/validated", (req, res) -> {
var isValidRequest = validateRequestSignature(requestValidator, webhookUrl, req);
if (!isValidRequest) {
res.status(401);
return "unauthorized";
}
return "<Response><Message>OK, you're valid by GET</Message></Response>";
});
post("/validated", (req, res) -> {
var isValidRequest = validateRequestSignature(requestValidator, webhookUrl, req);
if (!isValidRequest) {
res.status(401);
return "unauthorized";
}
return "<Response><Message>OK, you're valid by POST</Message></Response>";
});
}
private static boolean validateRequestSignature(RequestValidator requestValidator, String webhookUrl, spark.Request req) {
var twilioSignature = req.headers("X-Twilio-Signature");
var validationParams = new HashMap<String, String>();
if (req.requestMethod().equals("GET")){
// for GET requests, add the query string but don't add any params
// this will fail if the URL as provided in the PN config page already
// has query params.
webhookUrl += "?" + req.queryString();
} else { // POST
// Query params can (in theory) have multiple values. Twilio doesn't
// actually send any repeated values, hence `v[0]` below.
req.queryMap().toMap().forEach((k, v) -> validationParams.put(k, v[0]));
}
return requestValidator.validate(
webhookUrl,
validationParams,
twilioSignature);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment