1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
//! Verify that incoming requests are from Alexa for custom, webservice skills.
//!
//! - Confirmed working with the Alexa [certification functional test](https://developer.amazon.com/docs/devconsole/test-and-submit-your-skill.html).
//!
//! - Built using the [Developer Documentation](https://developer.amazon.com/docs/custom-skills/host-a-custom-skill-as-a-web-service.html#manually-verify-request-sent-by-alexa)
//! and [Python Alexa SDK](https://github.com/alexa/alexa-skills-kit-sdk-for-python/tree/master/ask-sdk-webservice-support)
//! as reference.
//!
//! # Features
//! Both sync and async clients are provided by default. These are behind feature
//! flags `sync` or `async`, respectively.
//!
//! - `sync` provides `RequestVerifier` client
//! - `async` provides `RequestVerifierAsync` client
//!
//! # Using
//! Example using [Rouille](https://github.com/tomaka/rouille) server
//! and [alexa_sdk](https://github.com/tarkah/alexa_rust) for request deserialization
//!
//! ```rust
//! use crate::skill::process_request; // Entry point to custom skill
//! use alexa_verifier::RequestVerifier; // Struct provided by this crate
//! use log::{debug, error, info};
//! use rouille::{router, Request, Response};
//! use std::io::Read;
//!
//! fn note_routes(request: &Request, verifier: &RequestVerifier) -> Response {
//! router!(request,
//! (POST) (/) => {
//! info!("Request received...");
//!
//! // Get request body data
//! let mut body = request.data().unwrap();
//! let mut body_bytes: Vec<u8> = vec![];
//! body.read_to_end(&mut body_bytes).unwrap();
//!
//! // Get needed headers, default to blank (will cause verification to fail)
//! let signature_cert_chain_url = request.header("SignatureCertChainUrl").unwrap_or("");
//! let signature = request.header("Signature").unwrap_or("");
//!
//! // Deserialize using alexa_sdk::Request
//! let _request = serde_json::from_slice::<alexa_sdk::Request>(&body_bytes);
//! if let Err(e) = _request {
//! error!("Could not deserialize request");
//! error!("{:?}", e);
//! let response = Response::empty_400();
//! info!("Sending back response...");
//! debug!("{:?}", response);
//! return response;
//! }
//! let request = _request.unwrap();
//! debug!("{:?}", request);
//!
//! // alexa-verifier used here, return 400 if verification fails
//! if verifier
//! .verify(
//! signature_cert_chain_url,
//! signature,
//! &body_bytes,
//! request.body.timestamp.as_str(),
//! None
//! ).is_err() {
//! error!("Could not validate request came from Alexa");
//! let response = Response::empty_400();
//! info!("Sending back response...");
//! debug!("{:?}", response);
//! return response;
//! };
//! debug!("Request is validated...");
//!
//! // Entry point custom to skill, returning alexa_sdk::Response
//! let response = Response::json(&process_request(request));
//! info!("Sending back response...");
//! debug!("{:?}", response);
//! response
//! },
//! _ => Response::empty_404()
//! )
//! }
//!
//! pub fn run() -> std::io::Result<()> {
//! info!("Starting server on 0.0.0.0:8086");
//! let verifier = RequestVerifier::new();
//!
//! rouille::start_server("0.0.0.0:8086", move |request| {
//! note_routes(&request, &verifier)
//! });
//! }
//! ```
//!
pub use RequestVerifier;
pub use r#RequestVerifierAsync;