Created
August 18, 2020 18:19
-
-
Save mjg123/4d8657750f77ed21ef6060bc3b580ce1 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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