diff --git a/app/controllers/twitch_stream_updates_controller.rb b/app/controllers/twitch_stream_updates_controller.rb index 93206983e..351fdbc60 100644 --- a/app/controllers/twitch_stream_updates_controller.rb +++ b/app/controllers/twitch_stream_updates_controller.rb @@ -35,10 +35,8 @@ class TwitchStreamUpdatesController < ApplicationController def secret_verified? twitch_sha = request.headers["x-hub-signature"] - digest = Digest::SHA256.new - digest << ApplicationConfig["TWITCH_WEBHOOK_SECRET"] - digest << request.raw_post + digest = OpenSSL::HMAC.hexdigest("SHA256", ApplicationConfig["TWITCH_WEBHOOK_SECRET"], request.raw_post) - twitch_sha == "sha256=#{digest.hexdigest}" + twitch_sha == "sha256=#{digest}" end end diff --git a/app/models/user.rb b/app/models/user.rb index 936ccfcaf..3b8db0c2e 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -504,6 +504,9 @@ class User < ApplicationRecord def bust_cache CacheBuster.new.bust("/#{username}") + CacheBuster.new.bust("/#{username}?i=i") + CacheBuster.new.bust("/live/#{username}") + CacheBuster.new.bust("/live/#{username}?i=i") CacheBuster.new.bust("/feed/#{username}") end handle_asynchronously :bust_cache diff --git a/app/services/streams/twitch_webhook/register.rb b/app/services/streams/twitch_webhook/register.rb index 8a5bdd6fa..2d6943923 100644 --- a/app/services/streams/twitch_webhook/register.rb +++ b/app/services/streams/twitch_webhook/register.rb @@ -34,7 +34,7 @@ module Streams "hub.lease_seconds" => WEBHOOK_LEASE_SECONDS, "hub.topic" => "https://api.twitch.tv/helix/streams?user_id=#{twitch_user_id}", "hub.secret" => ApplicationConfig["TWITCH_WEBHOOK_SECRET"] - }.to_json + } end def authentication_request_headers diff --git a/spec/requests/twitch_stream_updates_spec.rb b/spec/requests/twitch_stream_updates_spec.rb index cc0f752ea..91cdce246 100644 --- a/spec/requests/twitch_stream_updates_spec.rb +++ b/spec/requests/twitch_stream_updates_spec.rb @@ -41,35 +41,23 @@ RSpec.describe "TwitchStramUpdates", type: :request do end describe "POST /users/:user_id/twitch_stream_updates" do + before do + allow(ApplicationConfig).to receive(:[]).and_call_original + allow(ApplicationConfig).to receive(:[]).with("TWITCH_WEBHOOK_SECRET").and_return("FAKE_TWITCH_WEBHOOK_SECRET") + end + context "when the user was not streaming and starts streaming" do let(:currently_streaming_on) { nil } let(:twitch_webhook_params) do - { - data: [{ - id: "0123456789", - user_id: "5678", - user_name: "wjdtkdqhs", - game_id: "21779", - community_ids: [], - type: "live", - title: "Best Stream Ever", - viewer_count: 417, - started_at: "2017-12-01T10:09:45Z", - language: "en", - thumbnail_url: "https://link/to/thumbnail.jpg" - }] - } + '{"data":[{"id":"0123456789","user_id":"5678","user_name":"wjdtkdqhs","game_id":"21779","community_ids":[],"type":"live","title":"Best Stream Ever","viewer_count":417,"started_at":"2017-12-01T10:09:45Z","language":"en","thumbnail_url":"https://link/to/thumbnail.jpg"}]}' end let(:twitch_webhook_secret_sha) do - digest = Digest::SHA256.new - digest << ApplicationConfig["TWITCH_WEBHOOK_SECRET"] - digest << twitch_webhook_params.to_json - "sha256=#{digest.hexdigest}" + "sha256=96840ed4d83666551e43b384d94ac481367504564d6474b5dea710cedde5ce18" end it "updates the Users twitch streaming status" do - expect { post "/users/#{user.id}/twitch_stream_updates", params: twitch_webhook_params.to_json, headers: { "Content-Type" => "application/json", "X-Hub-Signature" => twitch_webhook_secret_sha } }. + expect { post "/users/#{user.id}/twitch_stream_updates", params: twitch_webhook_params, headers: { "Content-Type" => "application/json", "X-Hub-Signature" => twitch_webhook_secret_sha } }. to change { user.reload.currently_streaming? }.from(false).to(true). and change { user.reload.currently_streaming_on_twitch? }.from(false).to(true) end @@ -77,51 +65,32 @@ RSpec.describe "TwitchStramUpdates", type: :request do context "when the webhook secret was NOT verified" do let(:twitch_webhook_params) do - { - data: [{ - id: "0123456789", - user_id: "5678", - user_name: "wjdtkdqhs", - game_id: "21779", - community_ids: [], - type: "live", - title: "Best Stream Ever", - viewer_count: 417, - started_at: "2017-12-01T10:09:45Z", - language: "en", - thumbnail_url: "https://link/to/thumbnail.jpg" - }] - } + '{"data":[{"id":"0123456789","user_id":"5678","user_name":"wjdtkdqhs","game_id":"21779","community_ids":[],"type":"live","title":"Best Stream Ever","viewer_count":417,"started_at":"2017-12-01T10:09:45Z","language":"en","thumbnail_url":"https://link/to/thumbnail.jpg"}]}' end let(:twitch_webhook_secret_sha) { "sha256=BAD_HASH" } it "noops" do - expect { post "/users/#{user.id}/twitch_stream_updates", params: twitch_webhook_params.to_json, headers: { "Content-Type" => "application/json", "X-Hub-Signature" => twitch_webhook_secret_sha } }. + expect { post "/users/#{user.id}/twitch_stream_updates", params: twitch_webhook_params, headers: { "Content-Type" => "application/json", "X-Hub-Signature" => twitch_webhook_secret_sha } }. to not_change { user.reload.currently_streaming? }.from(false). and not_change { user.reload.currently_streaming_on_twitch? }.from(false) end end - end - context "when the user was streaming and stops" do - let(:currently_streaming_on) { :twitch } + context "when the user was streaming and stops" do + let(:currently_streaming_on) { :twitch } - let(:twitch_webhook_params) do - { - data: [] - } - end - let(:twitch_webhook_secret_sha) do - digest = Digest::SHA256.new - digest << ApplicationConfig["TWITCH_WEBHOOK_SECRET"] - digest << twitch_webhook_params.to_json - "sha256=#{digest.hexdigest}" - end + let(:twitch_webhook_params) do + '{"data":[]}' + end + let(:twitch_webhook_secret_sha) do + "sha256=3222cdd929339a296712edf3ec820266b1e29c0e4eeb715dd18d98c0c2294ca3" + end - it "updates the Users twitch streaming status" do - expect { post "/users/#{user.id}/twitch_stream_updates", params: twitch_webhook_params.to_json, headers: { "Content-Type" => "application/json", "X-Hub-Signature" => twitch_webhook_secret_sha } }. - to change { user.reload.currently_streaming? }.from(true).to(false). - and change { user.reload.currently_streaming_on_twitch? }.from(true).to(false) + it "updates the Users twitch streaming status" do + expect { post "/users/#{user.id}/twitch_stream_updates", params: twitch_webhook_params, headers: { "Content-Type" => "application/json", "X-Hub-Signature" => twitch_webhook_secret_sha } }. + to change { user.reload.currently_streaming? }.from(true).to(false). + and change { user.reload.currently_streaming_on_twitch? }.from(true).to(false) + end end end end diff --git a/spec/services/streams/twitch_webhook/register_spec.rb b/spec/services/streams/twitch_webhook/register_spec.rb index e3b39dbbf..9618563d0 100644 --- a/spec/services/streams/twitch_webhook/register_spec.rb +++ b/spec/services/streams/twitch_webhook/register_spec.rb @@ -15,11 +15,11 @@ RSpec.describe Streams::TwitchWebhook::Register, type: :service do "hub.lease_seconds" => 604_800, "hub.topic" => "https://api.twitch.tv/helix/streams?user_id=654321", "hub.secret" => ApplicationConfig["TWITCH_WEBHOOK_SECRET"] - }.to_json + } end let!(:twitch_webhook_registration_stubbed_route) do stub_request(:post, "https://api.twitch.tv/helix/webhooks/hub"). - with(body: expected_twitch_webhook_params, headers: expected_headers). + with(body: URI.encode_www_form(expected_twitch_webhook_params), headers: expected_headers). and_return(status: 204) end