using System.Threading.Tasks; using Myriad.Extensions; using Myriad.Rest.Exceptions; using Myriad.Rest.Types.Requests; using Myriad.Types; using PluralKit.Core; namespace PluralKit.Bot { public class Token { private readonly IDatabase _db; private readonly ModelRepository _repo; public Token(IDatabase db, ModelRepository repo) { _db = db; _repo = repo; } public async Task GetToken(Context ctx) { ctx.CheckSystem(); // Get or make a token var token = ctx.System.Token ?? await MakeAndSetNewToken(ctx.System); try { // DM the user a security disclaimer, and then the token in a separate message (for easy copying on mobile) var dm = await ctx.Cache.GetOrCreateDmChannel(ctx.Rest, ctx.Author.Id); await ctx.Rest.CreateMessage(dm.Id, new MessageRequest { Content = $"{Emojis.Warn} Please note that this grants access to modify (and delete!) all your system data, so keep it safe and secure. If it leaks or you need a new one, you can invalidate this one with `pk;token refresh`.\n\nYour token is below:" }); await ctx.Rest.CreateMessage(dm.Id, new MessageRequest {Content = token}); // If we're not already in a DM, reply with a reminder to check if (ctx.Channel.Type != Channel.ChannelType.Dm) await ctx.Reply($"{Emojis.Success} Check your DMs!"); } catch (ForbiddenException) { // Can't check for permission errors beforehand, so have to handle here :/ if (ctx.Channel.Type != Channel.ChannelType.Dm) await ctx.Reply($"{Emojis.Error} Could not send token in DMs. Are your DMs closed?"); } } private async Task MakeAndSetNewToken(PKSystem system) { var patch = new SystemPatch {Token = StringUtils.GenerateToken()}; system = await _db.Execute(conn => _repo.UpdateSystem(conn, system.Id, patch)); return system.Token; } public async Task RefreshToken(Context ctx) { ctx.CheckSystem(); if (ctx.System.Token == null) { // If we don't have a token, call the other method instead // This does pretty much the same thing, except words the messages more appropriately for that :) await GetToken(ctx); return; } try { // DM the user an invalidation disclaimer, and then the token in a separate message (for easy copying on mobile) var dm = await ctx.Cache.GetOrCreateDmChannel(ctx.Rest, ctx.Author.Id); await ctx.Rest.CreateMessage(dm.Id, new MessageRequest { Content = $"{Emojis.Warn} Your previous API token has been invalidated. You will need to change it anywhere it's currently used.\n\nYour token is below:" }); // Make the new token after sending the first DM; this ensures if we can't DM, we also don't end up // breaking their existing token as a side effect :) var token = await MakeAndSetNewToken(ctx.System); await ctx.Rest.CreateMessage(dm.Id, new MessageRequest { Content = token }); // If we're not already in a DM, reply with a reminder to check if (ctx.Channel.Type != Channel.ChannelType.Dm) await ctx.Reply($"{Emojis.Success} Check your DMs!"); } catch (ForbiddenException) { // Can't check for permission errors beforehand, so have to handle here :/ if (ctx.Channel.Type != Channel.ChannelType.Dm) await ctx.Reply($"{Emojis.Error} Could not send token in DMs. Are your DMs closed?"); } } } }