173 lines
6.4 KiB
C#
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}";
|
|
}
|
|
}
|
|
} |