using System; using System.Collections.Generic; using System.IO; using System.Net; using System.Net.Http; using System.Text; using System.Threading.Tasks; using Newtonsoft.Json; using TwitchEventSub.Types.EventSubSubscription; using System.Security.Cryptography; using System.Linq; namespace TwitchEventSub { public class Receiver { private OAuthToken token; private HttpListener server; static readonly HttpClient client = new HttpClient(); public Dictionary> psuedoResources { get; set; } = new Dictionary>(); private string hmacSecret = ""; private bool going = false; private Uri publicUrl; private Queue twitchogrambuffer { get; set; } private string clientId; private HMACSHA256 hmacsha256 = null; private List tasksToNotActuallyAwait = new List(); public Receiver(HttpListener server, string clientId, string clientSecret, string publicUrl) { this.clientId = clientId; this.publicUrl = new Uri(publicUrl + "/twitcherize"); twitchogrambuffer = new Queue(); this.server = server; authorizeClient(clientId, clientSecret); clearOldSubscriptions(); prepareHmac(); } private void prepareHmac() { var r = new Random(); var stringLength = r.Next(20, 100); var charChoices = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; for (int i = 0; i < stringLength; i++) { this.hmacSecret += charChoices[r.Next(charChoices.Length)]; } this.hmacsha256 = new HMACSHA256(Encoding.ASCII.GetBytes(this.hmacSecret)); } private void authorizeClient(string clientId, string clientSecret) { Console.WriteLine($"got a token"); client.DefaultRequestHeaders.Add("Client-ID", $"{this.clientId }"); client.DefaultRequestHeaders.Add("Authorization", $"Bearer {this.token.access_token}"); } private void clearOldSubscriptions() { var r = client.GetAsync("https://api.twitch.tv/helix/eventsub/subscriptions").Result; var responseText = ""; using (var streamReader = new StreamReader(r.Content.ReadAsStream())) { responseText = streamReader.ReadToEnd(); } if(!r.IsSuccessStatusCode) { Console.Error.WriteLine(responseText); throw new Exception(responseText); } var listing = SubscribableTypesTranslation.RefineTwitchResponse(responseText); var deletes = new List>(); foreach(var subscription in listing.data) { deletes.Add(client.DeleteAsync($"https://api.twitch.tv/helix/eventsub/subscriptions?id={subscription.id}")); } Task.WaitAll(deletes.ToArray()); } public void Subscribe(SubscribableTypes type, c condition, Action handler) where c : Types.Conditions.Condition { if (!going) { Task.Run(go); } var subreq = new Request() { condition = condition, transport = new Transport() { callback = publicUrl, secret = hmacSecret }, type = SubscribableTypesTranslation.Enum2String(type), version = "1" }; var subAsString = JsonConvert.SerializeObject(subreq); var content = new StringContent(subAsString, Encoding.UTF8, "application/json"); var r = client.PostAsync("https://api.twitch.tv/helix/eventsub/subscriptions", content).Result; string responseText; using (var streamReader = new StreamReader(r.Content.ReadAsStream())) { responseText = streamReader.ReadToEnd(); } var tr = SubscribableTypesTranslation.RefineTwitchResponse(responseText); var firstSubscription = tr.data?.FirstOrDefault(); if(firstSubscription != null) { psuedoResources.Add(firstSubscription, handler); } } public async Task go() { going = true; await Task.Run(() => { }); going = false; } private async Task logMessageId(string id) { lock(twitchogrambuffer) { twitchogrambuffer.Enqueue(id); } await Task.Delay(2000); string x; lock(twitchogrambuffer) { twitchogrambuffer.TryDequeue(out x); } } private bool VerifySignature(string signature, Encoding encoder, string messageId, string timestamp, byte[] rawIncomingBytes) { var hashables = new List(); hashables.Add(encoder.GetBytes(messageId + timestamp).Concat(rawIncomingBytes).ToArray()); hashables.Add(encoder.GetBytes(messageId.ToLower() + timestamp).Concat(rawIncomingBytes).ToArray()); hashables.Add(encoder.GetBytes(messageId.ToLower() + timestamp.ToLower()).Concat(rawIncomingBytes).ToArray()); hashables.Add(encoder.GetBytes(messageId + timestamp.ToLower()).Concat(rawIncomingBytes).ToArray()); var computeds = new List(); foreach(var hashable in hashables) { computeds.Add("sha256=" + Convert.ToHexString(hmacsha256.ComputeHash(hashable)).ToLower()); // var hashed = computeds.Last(); // if(signature?.ToLower() == hashed) // { // Console.Write(" * "); // } // else // { // Console.Write(" "); // } // Console.WriteLine(computeds.Last()); } return computeds.Contains(signature?.ToLower()); //Console.WriteLine($"{signature?.ToLower()} == sha256={computed}?"); //return signature?.ToLower() == $"sha256={computed}"; } } }