Add API token commands
This commit is contained in:
parent
7a10a28019
commit
06edc9d61e
66
PluralKit.Bot/Commands/APICommands.cs
Normal file
66
PluralKit.Bot/Commands/APICommands.cs
Normal file
@ -0,0 +1,66 @@
|
||||
using System.Threading.Tasks;
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
|
||||
namespace PluralKit.Bot.Commands
|
||||
{
|
||||
[Group("token")]
|
||||
public class APICommands: ModuleBase<PKCommandContext>
|
||||
{
|
||||
public SystemStore Systems { get; set; }
|
||||
|
||||
[Command]
|
||||
[MustHaveSystem]
|
||||
[Remarks("token")]
|
||||
public async Task GetToken()
|
||||
{
|
||||
// Get or make a token
|
||||
var token = Context.SenderSystem.Token ?? await MakeAndSetNewToken();
|
||||
|
||||
// If we're not already in a DM, reply with a reminder to check
|
||||
if (!(Context.Channel is IDMChannel))
|
||||
{
|
||||
await Context.Channel.SendMessageAsync($"{Emojis.Success} Check your DMs!");
|
||||
}
|
||||
|
||||
// DM the user a security disclaimer, and then the token in a separate message (for easy copying on mobile)
|
||||
await Context.User.SendMessageAsync($"{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 Context.User.SendMessageAsync(token);
|
||||
}
|
||||
|
||||
private async Task<string> MakeAndSetNewToken()
|
||||
{
|
||||
Context.SenderSystem.Token = PluralKit.Utils.GenerateToken();
|
||||
await Systems.Save(Context.SenderSystem);
|
||||
return Context.SenderSystem.Token;
|
||||
}
|
||||
|
||||
[Command("refresh")]
|
||||
[MustHaveSystem]
|
||||
[Alias("expire", "invalidate", "update", "new")]
|
||||
[Remarks("token refresh")]
|
||||
public async Task RefreshToken()
|
||||
{
|
||||
if (Context.SenderSystem.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();
|
||||
return;
|
||||
}
|
||||
|
||||
// Make a new token from scratch
|
||||
var token = await MakeAndSetNewToken();
|
||||
|
||||
// If we're not already in a DM, reply with a reminder to check
|
||||
if (!(Context.Channel is IDMChannel))
|
||||
{
|
||||
await Context.Channel.SendMessageAsync($"{Emojis.Success} Check your DMs!");
|
||||
}
|
||||
|
||||
// DM the user an invalidation disclaimer, and then the token in a separate message (for easy copying on mobile)
|
||||
await Context.User.SendMessageAsync($"{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:");
|
||||
await Context.User.SendMessageAsync(token);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,8 +1,6 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text.RegularExpressions;
|
||||
using NodaTime;
|
||||
using NodaTime.Text;
|
||||
@ -24,6 +22,13 @@ namespace PluralKit
|
||||
return hid;
|
||||
}
|
||||
|
||||
public static string GenerateToken()
|
||||
{
|
||||
var buf = new byte[48]; // Results in a 64-byte Base64 string (no padding)
|
||||
new RNGCryptoServiceProvider().GetBytes(buf);
|
||||
return Convert.ToBase64String(buf);
|
||||
}
|
||||
|
||||
public static string Truncate(this string str, int maxLength, string ellipsis = "...") {
|
||||
if (str.Length < maxLength) return str;
|
||||
return str.Substring(0, maxLength - ellipsis.Length) + ellipsis;
|
||||
@ -225,21 +230,19 @@ namespace PluralKit
|
||||
{
|
||||
public static IPattern<Instant> TimestampExportFormat = InstantPattern.CreateWithInvariantCulture("g");
|
||||
public static IPattern<LocalDate> DateExportFormat = LocalDatePattern.CreateWithInvariantCulture("yyyy-MM-dd");
|
||||
public static IPattern<Duration> DurationFormat;
|
||||
|
||||
// We create a composite pattern that only shows the two most significant things
|
||||
// eg. if we have something with nonzero day component, we show <x>d <x>h, but if it's
|
||||
// a smaller duration we may only bother with showing <x>h <x>m or <x>m <x>s
|
||||
public static IPattern<Duration> DurationFormat = new CompositePatternBuilder<Duration>
|
||||
{
|
||||
{DurationPattern.CreateWithInvariantCulture("D'd' h'h'"), d => d.Days > 0},
|
||||
{DurationPattern.CreateWithInvariantCulture("H'h' m'm'"), d => d.Hours > 0},
|
||||
{DurationPattern.CreateWithInvariantCulture("m'm' s's'"), d => d.Minutes > 0},
|
||||
{DurationPattern.CreateWithInvariantCulture("s's'"), d => true}
|
||||
}.Build();
|
||||
|
||||
public static IPattern<LocalDateTime> LocalDateTimeFormat = LocalDateTimePattern.CreateWithInvariantCulture("yyyy-MM-dd HH:mm:ss");
|
||||
public static IPattern<ZonedDateTime> ZonedDateTimeFormat = ZonedDateTimePattern.CreateWithInvariantCulture("yyyy-MM-dd HH:mm:ss x", DateTimeZoneProviders.Tzdb);
|
||||
|
||||
static Formats()
|
||||
{
|
||||
// We create a composite pattern that only shows the two most significant things
|
||||
// eg. if we have something with nonzero day component, we show <x>d <x>h, but if it's
|
||||
// a smaller duration we may only bother with showing <x>h <x>m or <x>m <x>s
|
||||
var compositeDuration = new CompositePatternBuilder<Duration>();
|
||||
compositeDuration.Add(DurationPattern.CreateWithInvariantCulture("D'd' h'h'"), d => d.Days > 0);
|
||||
compositeDuration.Add(DurationPattern.CreateWithInvariantCulture("H'h' m'm'"), d => d.Hours > 0);
|
||||
compositeDuration.Add(DurationPattern.CreateWithInvariantCulture("m'm' s's'"), d => d.Minutes > 0);
|
||||
compositeDuration.Add(DurationPattern.CreateWithInvariantCulture("s's'"), d => true);
|
||||
DurationFormat = compositeDuration.Build();
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user