twitch-agent/TwitchEventSub/Receiver.cs
2022-01-16 15:10:20 -05:00

173 lines
6.4 KiB
C#

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<Subscription, Action<Twitchogram>> psuedoResources { get; set; }
= new Dictionary<Subscription, Action<Twitchogram>>();
private string hmacSecret = "";
private bool going = false;
private Uri publicUrl;
private Queue<string> twitchogrambuffer { get; set; }
private string clientId;
private HMACSHA256 hmacsha256 = null;
private List<Task> tasksToNotActuallyAwait = new List<Task>();
public Receiver(HttpListener server, string clientId, string clientSecret, string publicUrl)
{
this.clientId = clientId;
this.publicUrl = new Uri(publicUrl + "/twitcherize");
twitchogrambuffer = new Queue<string>();
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<Task<HttpResponseMessage>>();
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<c>(SubscribableTypes type, c condition, Action<Twitchogram> 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<byte[]>();
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<string>();
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}";
}
}
}