using System; using System.Collections.Generic; using System.Linq; using System.Net.Http; using System.Net.Http.Headers; using System.Threading.Tasks; using ChaosBot.Discord; using ChaosBot.Repositories; using ChaosBot.WebServer.Services; using Discord; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Configuration; using Newtonsoft.Json; namespace ChaosBot.WebServer.App { [ApiController] [Route("/api/discord")] public class DiscordController : Controller { private readonly AccessTokenCache _accessTokenCache; private static HttpClient _httpClient; private readonly DiscordInviteGenerator _inviteGenerator; public DiscordController( AccessTokenCache accessTokenCache, DiscordInviteGenerator inviteGenerator, HttpClient httpClient ) { _accessTokenCache = accessTokenCache; _inviteGenerator = inviteGenerator; _httpClient = httpClient; } [HttpGet] public async Task Index(string code = null) { Configuration config = new Configuration(); string redirectUri = $"{config.GetValue("Discord:BaseUri")}/api/discord"; string clientId = config.GetValue("Discord:ClientId"); string clientSecret = config.GetValue("Discord:ClientSecret"); if (code == null) return Redirect($"https://discord.com/api/oauth2/authorize?client_id={clientId}&redirect_uri={redirectUri}&response_type=code&scope=identify%20guilds"); Dictionary values = new Dictionary { { "client_id", clientId }, { "client_secret", clientSecret }, { "grant_type", "authorization_code" }, { "code", code }, { "redirect_uri", redirectUri }, { "scope", "identify guild" } }; FormUrlEncodedContent content = new FormUrlEncodedContent(values); HttpResponseMessage response = await _httpClient.PostAsync("https://discord.com/api/oauth2/token", content); string responseString = await response.Content.ReadAsStringAsync(); DiscordOauthResponse responseObject = JsonConvert.DeserializeObject(responseString); DiscordUserResponse userResponse = GetDiscordUser(responseObject.access_token); if (_accessTokenCache.HasKey(responseObject.access_token)) _accessTokenCache.Remove(responseObject.access_token); _accessTokenCache.Add(responseObject.access_token, userResponse.id, DateTime.Now.AddSeconds(responseObject.expires_in)); return LocalRedirect($"/#/?access_token={responseObject.access_token}"); } [HttpGet("invite")] public IActionResult Invite() { return Redirect(_inviteGenerator.Generate()); } [HttpGet("user")] public IActionResult GetUser() { if (!Request.Cookies.TryGetValue("access_token", out string accessToken)) accessToken = null; DiscordUserResponse userResponse = GetDiscordUser(accessToken); return Json(userResponse); } [HttpGet("guilds")] public IActionResult GetGuilds() { if (!Request.Cookies.TryGetValue("access_token", out string accessToken)) accessToken = null; HttpResponseMessage response; using (HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Get, "https://discord.com/api/v7/users/@me/guilds")) { requestMessage.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken); response = _httpClient.SendAsync(requestMessage).GetAwaiter().GetResult(); } string responseString = response.Content.ReadAsStringAsync().GetAwaiter().GetResult(); List userResponse = JsonConvert.DeserializeObject>(responseString); List presentGuilds = DiscordConnect._client.Guilds.Select(g => g.Id).ToList(); List userResponseWithPresence = userResponse .Select(guild => guild.AddPresence(presentGuilds.Contains(Convert.ToUInt64(guild.id)))) .ToList(); return Json(userResponseWithPresence); } private static DiscordUserResponse GetDiscordUser(string accessToken) { HttpResponseMessage response; using (HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Get, "https://discord.com/api/v7/users/@me")) { requestMessage.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken); response = _httpClient.SendAsync(requestMessage).GetAwaiter().GetResult(); } string responseString = response.Content.ReadAsStringAsync().GetAwaiter().GetResult(); DiscordUserResponse userResponse = JsonConvert.DeserializeObject(responseString); return userResponse; } } internal class DiscordOauthResponse { public string error { get; set; } = null; public string error_description { get; set; } = null; public string access_token { get; set; } = null; public int expires_in { get; set; } = 0; public string refresh_token { get; set; } = null; public string scope { get; set; } = null; public string token_type { get; set; } = null; } public class DiscordUserResponse { public string id { get; set; } public string username { get; set; } public string discriminator { get; set; } public string avatar { get; set; } = null; public bool bot { get; set; } = false; public bool system { get; set; } = false; public bool mfa_enabled { get; set; } = false; public string locale { get; set; } = null; public bool verified { get; set; } = false; public string email { get; set; } = null; public int flags { get; set; } = 0; public int premium_type { get; set; } = 0; public int public_flags { get; set; } = 0; } public class DiscordGuildResponse { public string id { get; set; } public string name { get; set; } public string icon { get; set; } public bool owner { get; set; } public int permissions { get; set; } public int permissions_new { get; set; } public DiscordGuildResponseWithPresence AddPresence(bool presence) { return new DiscordGuildResponseWithPresence { id = id, name = name, icon = icon, owner = owner, permissions = permissions, permissions_new = permissions_new, bot_present = presence }; } } public class DiscordGuildResponseWithPresence : DiscordGuildResponse { public bool bot_present { get; set; } } }