diff --git a/Cargo.lock b/Cargo.lock index 850506f..c7a2bbf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1262,6 +1262,33 @@ dependencies = [ "syn", ] +[[package]] +name = "ring" +version = "0.16.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +dependencies = [ + "cc", + "libc", + "once_cell", + "spin", + "untrusted", + "web-sys", + "winapi", +] + +[[package]] +name = "rustls" +version = "0.20.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fbfeb8d0ddb84706bc597a5574ab8912817c52a397f819e5b614e2265206921" +dependencies = [ + "log", + "ring", + "sct", + "webpki", +] + [[package]] name = "rustversion" version = "1.0.6" @@ -1302,6 +1329,16 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +[[package]] +name = "sct" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" +dependencies = [ + "ring", + "untrusted", +] + [[package]] name = "security-framework" version = "2.6.1" @@ -1476,6 +1513,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + [[package]] name = "static_assertions" version = "1.1.0" @@ -1616,6 +1659,17 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-rustls" +version = "0.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a27d5f2b839802bd8267fa19b0530f5a08b9c08cd417976be2a65d130fe1c11b" +dependencies = [ + "rustls", + "tokio", + "webpki", +] + [[package]] name = "tokio-stream" version = "0.1.8" @@ -1648,8 +1702,12 @@ checksum = "06cda1232a49558c46f8a504d5b93101d42c0bf7f911f12a105ba48168f821ae" dependencies = [ "futures-util", "log", + "rustls", "tokio", + "tokio-rustls", "tungstenite 0.17.2", + "webpki", + "webpki-roots", ] [[package]] @@ -1740,10 +1798,12 @@ dependencies = [ "httparse", "log", "rand", + "rustls", "sha-1 0.10.0", "thiserror", "url", "utf-8", + "webpki", ] [[package]] @@ -1847,6 +1907,12 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + [[package]] name = "url" version = "2.2.2" @@ -2015,6 +2081,25 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "webpki" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "webpki-roots" +version = "0.22.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "552ceb903e957524388c4d3475725ff2c8b7960922063af6ce53c9a43da07449" +dependencies = [ + "webpki", +] + [[package]] name = "winapi" version = "0.3.9" diff --git a/Cargo.toml b/Cargo.toml index 59781c1..8bdb83c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,7 +21,7 @@ serde = { version = "1", features = ["derive"] } serde_json = "1" serde_with = { version = "1", features = ["chrono"] } toml = "0.5" -tokio-tungstenite = { version = "0.17" } +tokio-tungstenite = { version = "0.17", features = ["rustls-tls-webpki-roots"] } twitch_api2 = { version = "0.6.0-rc.3", features = ["twitch_oauth2", "client", "reqwest_client", "helix", "pubsub", "unsupported"] } url = "2" uuid = { version = "0.8", features = ["v4", "serde"] } diff --git a/src/app/twitch.rs b/src/app/twitch.rs index 488bd45..51534a4 100644 --- a/src/app/twitch.rs +++ b/src/app/twitch.rs @@ -43,7 +43,7 @@ impl Twitch { let mut user_token = self.config.read().await.user_token.as_ref().unwrap().clone(); if user_token.token.expires_in() <= std::time::Duration::from_secs(60 * 15) { user_token.refresh_token(&reqwest::Client::new()).await?; - self.config.write().await.bot_token.replace(user_token.clone()); + self.config.write().await.user_token.replace(user_token.clone()); } Ok(user_token.token) diff --git a/src/app/web/route/livesplit.rs b/src/app/web/route/livesplit.rs index d77a8d3..2daf7d9 100644 --- a/src/app/web/route/livesplit.rs +++ b/src/app/web/route/livesplit.rs @@ -47,8 +47,8 @@ const REWARDS: &[RewardPauseInfo] = &[ ]; const REQUIRE_OPEN_LIVESPLIT: &[&str] = &[ - "7b66ffcd-8bd3-44c2-8d1d-3bc5ab1fa6ff", - "a598e71b-4521-4d74-8099-2859a81c4233", + "2205b59c-62d4-4dc1-bf27-2a96f3fcf2ca", + "3ea308c5-eeb8-4c46-88a5-d12555257b61", ]; async fn set_reward_paused(state: Arc, id: String, paused: bool) -> anyhow::Result<()> { @@ -61,6 +61,7 @@ async fn set_reward_paused(state: Arc, id: String, paused: bool) -> anyho .build(); state.twitch.client.helix.req_patch(request, body, &state.twitch.user_token().await?).await?; + Ok(()) } diff --git a/src/app/web/route/redemptions.rs b/src/app/web/route/redemptions.rs index 1b3b1a6..911e978 100644 --- a/src/app/web/route/redemptions.rs +++ b/src/app/web/route/redemptions.rs @@ -1,5 +1,5 @@ use twitch_api2::{ - helix::points::{GetCustomRewardRequest, CustomReward}, + helix::points::{CreateCustomRewardRequest, CreateCustomRewardBody, GetCustomRewardRequest, CustomReward}, types::RewardId, }; use warp::{ @@ -13,7 +13,7 @@ use crate::app::{ config::Redemption, web::{ CustomRejection, - template::redemptions::{RedemptionsTemplate, AddRedemptionTemplate, ListRedemptionsTemplate}, + template::redemptions::{RedemptionsTemplate, AddRedemptionTemplate, CreateRedemptionTemplate, ListRedemptionsTemplate}, }, }; use std::{ @@ -28,10 +28,12 @@ pub fn redemptions_routes(state: Arc) -> BoxedFilter<(impl Reply, )> { redemptions_get(Arc::clone(&state)) .or(redemptions_add_get()) .or(redemptions_list_get(Arc::clone(&state))) + .or(redemptions_create_get()) ) .or(warp::post().and( redemptions_add_post(Arc::clone(&state)) .or(redemptions_delete_post(Arc::clone(&state))) + .or(redemptions_create_post(Arc::clone(&state))) )) .boxed() } @@ -94,6 +96,57 @@ fn redemptions_add_post(state: Arc) -> BoxedFilter<(impl Reply, )> { .boxed() } +fn redemptions_create_get() -> BoxedFilter<(impl Reply, )> { + warp::path("redemptions") + .and(warp::path("create")) + .and(warp::path::end()) + .map(|| CreateRedemptionTemplate) + .boxed() +} + +fn redemptions_create_post(state: Arc) -> BoxedFilter<(impl Reply, )> { + warp::path("redemptions") + .and(warp::path("create")) + .and(warp::path::end()) + .and(warp::body::content_length_limit(1024 * 5)) + .and(warp::body::form()) + .and_then(move |mut form: HashMap| { + let state = Arc::clone(&state); + async move { + let form_get = try { + let name = form.remove("name")?; + name + }; + + let name = match form_get { + Some(x) => x, + None => return Err(warp::reject::custom(CustomRejection::InvalidForm)), + }; + + let request = CreateCustomRewardRequest::builder() + .broadcaster_id(state.user_config.twitch.channel_id.to_string()) + .build(); + + let body = CreateCustomRewardBody::builder() + .title(name) + .cost(100) + .build(); + + let token = match state.twitch.user_token().await { + Ok(token) => token, + Err(_) => return Err(warp::reject::custom(CustomRejection::TwitchError)), + }; + let _reward: CustomReward = match state.twitch.client.helix.req_post(request, body, &token).await { + Ok(resp) => resp.data, + Err(_) => return Err(warp::reject::custom(CustomRejection::TwitchError)), + }; + + Ok(warp::redirect(Uri::from_static("/redemptions/list"))) + } + }) + .boxed() +} + fn redemptions_delete_post(state: Arc) -> BoxedFilter<(impl Reply, )> { warp::path("redemptions") .and(warp::path("delete")) diff --git a/src/app/web/template/redemptions.rs b/src/app/web/template/redemptions.rs index acfcd88..bfee7f8 100644 --- a/src/app/web/template/redemptions.rs +++ b/src/app/web/template/redemptions.rs @@ -17,3 +17,7 @@ pub struct AddRedemptionTemplate; pub struct ListRedemptionsTemplate { pub rewards: Vec, } + +#[derive(Template)] +#[template(path = "create_redemption.html")] +pub struct CreateRedemptionTemplate; diff --git a/templates/create_redemption.html b/templates/create_redemption.html new file mode 100644 index 0000000..b674f64 --- /dev/null +++ b/templates/create_redemption.html @@ -0,0 +1,18 @@ +{% extends "_base.html" %} + +{% block title %}Create redemption{% endblock %} + +{% block body %} + + +
+ + +
+{% endblock %}