sys/sysmod/http/
line_hook.rs

1//! LINE Webhook.
2//!
3//! <https://developers.line.biz/ja/docs/messaging-api/>
4
5use super::{ActixError, WebResult};
6use crate::taskserver::Control;
7
8use actix_web::{HttpRequest, HttpResponse, Responder, http::header::ContentType, web};
9use log::info;
10
11#[actix_web::get("/line/")]
12async fn index_get() -> impl Responder {
13    let body = r#"<!DOCTYPE html>
14<html lang="en">
15  <head>
16    <title>LINE Webhook</title>
17  </head>
18  <body>
19    <h1>LINE Webhook</h1>
20    <p>Your request is GET.</p>
21  </body>
22</html>
23"#;
24
25    HttpResponse::Ok()
26        .content_type(ContentType::html())
27        .body(body)
28}
29
30#[actix_web::post("/line/")]
31async fn index_post(req: HttpRequest, body: String, ctrl: web::Data<Control>) -> WebResult {
32    info!("LINE github webhook");
33
34    // get signature
35    let headers = req.headers();
36    let signature = if let Some(s) = headers.get("x-line-signature") {
37        if let Ok(s) = s.to_str() {
38            s
39        } else {
40            return Err(ActixError::new("Bad x-line-signature header", 400));
41        }
42    } else {
43        return Err(ActixError::new("x-line-signature required", 400));
44    };
45    info!("x-line-signature: {signature}");
46
47    {
48        let line = ctrl.sysmods().line.lock().await;
49        // verify signature
50        if let Err(err) = line.verify_signature(signature, &body) {
51            return Err(ActixError::new(&err.to_string(), 401));
52        }
53
54        if let Err(e) = line.process_post(&body) {
55            return Err(ActixError::new(&e.to_string(), 400));
56        }
57    }
58    Ok(HttpResponse::Ok()
59        .content_type(ContentType::plaintext())
60        .body(""))
61}