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
pub use facebook_fb_login_deauth_callback;
use std::{collections::HashMap, convert::Infallible, error, sync::Arc};
use facebook_fb_login_deauth_callback::{
get::PASS_BACK_STATUS_CODE,
post::{pass_back_with_signed_request, PassBackCallbackFn, SIGNED_REQUEST_FORM_KEY},
};
use warp::{
http::{Response, StatusCode},
hyper::Body,
Filter,
};
pub trait Context: Send + Sync + Clone {
fn get_app_secret(&self, app_id: u64) -> Result<String, Box<dyn error::Error + Send + Sync>>;
}
pub fn handle<C: Context>(
path_prefix: String,
ctx: C,
callback: PassBackCallbackFn<'static, C>,
) -> impl Filter<Extract = (impl warp::Reply,), Error = warp::Rejection> + Clone {
get_filter(path_prefix.clone(), ctx.clone()).or(post_filter(
path_prefix,
ctx,
Arc::new(callback),
))
}
fn get_filter<C: Context>(
path_prefix: String,
ctx: C,
) -> impl Filter<Extract = (impl warp::Reply,), Error = warp::Rejection> + Clone {
warp::path(path_prefix)
.and(warp::path::param::<u64>())
.and(warp::path::end())
.and(warp::get())
.and_then(move |app_id| {
let ctx = ctx.clone();
async move {
let part: Result<Result<Response<Body>, warp::http::Error>, Infallible> = {
match ctx.get_app_secret(app_id) {
Ok(_) => Ok(Response::builder()
.status(PASS_BACK_STATUS_CODE)
.body("".into())),
Err(err) => Ok(Response::builder()
.status(StatusCode::INTERNAL_SERVER_ERROR)
.body(err.to_string().into())),
}
};
part
}
})
}
fn post_filter<C: Context>(
path_prefix: String,
ctx: C,
callback: Arc<PassBackCallbackFn<'static, C>>,
) -> impl Filter<Extract = (impl warp::Reply,), Error = warp::Rejection> + Clone {
warp::path(path_prefix)
.and(warp::path::param::<u64>())
.and(warp::path::end())
.and(warp::post())
.and(warp::body::content_length_limit(1024 * 32).and(warp::body::form()))
.and_then(move |app_id: u64, request_form: HashMap<String, String>| {
let ctx = ctx.clone();
let callback = callback.clone();
async move {
let part: Result<Result<Response<Body>, warp::http::Error>, Infallible> = {
match request_form.get(SIGNED_REQUEST_FORM_KEY) {
Some(signed_request) => match ctx.get_app_secret(app_id) {
Ok(app_secret) => {
let res = pass_back_with_signed_request(
signed_request,
&app_secret,
ctx,
callback,
)
.await;
Ok(Response::builder()
.status(res.status_code)
.body(res.body.into()))
}
Err(err) => Ok(Response::builder()
.status(StatusCode::INTERNAL_SERVER_ERROR)
.body(err.to_string().into())),
},
None => Ok(Response::builder()
.status(StatusCode::BAD_REQUEST)
.body("form invalid".into())),
}
};
part
}
})
}