DiscordChatExporter/DiscordChatExporter.Gui/Services/SettingsService.TokenEncryptionConverter.cs
Tyrrrz d490fd0a38
Some checks are pending
docker / pack (push) Waiting to run
docker / deploy (push) Waiting to run
main / format (push) Waiting to run
main / test (push) Waiting to run
main / pack (DiscordChatExporter.Cli, DiscordChatExporter.Cli, linux-arm) (push) Waiting to run
main / pack (DiscordChatExporter.Cli, DiscordChatExporter.Cli, linux-arm64) (push) Waiting to run
main / pack (DiscordChatExporter.Cli, DiscordChatExporter.Cli, linux-musl-x64) (push) Waiting to run
main / pack (DiscordChatExporter.Cli, DiscordChatExporter.Cli, linux-x64) (push) Waiting to run
main / pack (DiscordChatExporter.Cli, DiscordChatExporter.Cli, osx-arm64) (push) Waiting to run
main / pack (DiscordChatExporter.Cli, DiscordChatExporter.Cli, osx-x64) (push) Waiting to run
main / pack (DiscordChatExporter.Cli, DiscordChatExporter.Cli, win-arm64) (push) Waiting to run
main / pack (DiscordChatExporter.Cli, DiscordChatExporter.Cli, win-x64) (push) Waiting to run
main / pack (DiscordChatExporter.Cli, DiscordChatExporter.Cli, win-x86) (push) Waiting to run
main / pack (DiscordChatExporter.Gui, DiscordChatExporter, linux-arm) (push) Waiting to run
main / pack (DiscordChatExporter.Gui, DiscordChatExporter, linux-arm64) (push) Waiting to run
main / pack (DiscordChatExporter.Gui, DiscordChatExporter, linux-musl-x64) (push) Waiting to run
main / pack (DiscordChatExporter.Gui, DiscordChatExporter, linux-x64) (push) Waiting to run
main / pack (DiscordChatExporter.Gui, DiscordChatExporter, osx-arm64) (push) Waiting to run
main / pack (DiscordChatExporter.Gui, DiscordChatExporter, osx-x64) (push) Waiting to run
main / pack (DiscordChatExporter.Gui, DiscordChatExporter, win-arm64) (push) Waiting to run
main / pack (DiscordChatExporter.Gui, DiscordChatExporter, win-x64) (push) Waiting to run
main / pack (DiscordChatExporter.Gui, DiscordChatExporter, win-x86) (push) Waiting to run
main / release (push) Blocked by required conditions
main / deploy (DiscordChatExporter.Cli, DiscordChatExporter.Cli, linux-arm) (push) Blocked by required conditions
main / deploy (DiscordChatExporter.Cli, DiscordChatExporter.Cli, linux-arm64) (push) Blocked by required conditions
main / deploy (DiscordChatExporter.Cli, DiscordChatExporter.Cli, linux-musl-x64) (push) Blocked by required conditions
main / deploy (DiscordChatExporter.Cli, DiscordChatExporter.Cli, linux-x64) (push) Blocked by required conditions
main / deploy (DiscordChatExporter.Cli, DiscordChatExporter.Cli, osx-arm64) (push) Blocked by required conditions
main / deploy (DiscordChatExporter.Cli, DiscordChatExporter.Cli, osx-x64) (push) Blocked by required conditions
main / deploy (DiscordChatExporter.Cli, DiscordChatExporter.Cli, win-arm64) (push) Blocked by required conditions
main / deploy (DiscordChatExporter.Cli, DiscordChatExporter.Cli, win-x64) (push) Blocked by required conditions
main / deploy (DiscordChatExporter.Cli, DiscordChatExporter.Cli, win-x86) (push) Blocked by required conditions
main / deploy (DiscordChatExporter.Gui, DiscordChatExporter, linux-arm) (push) Blocked by required conditions
main / deploy (DiscordChatExporter.Gui, DiscordChatExporter, linux-arm64) (push) Blocked by required conditions
main / deploy (DiscordChatExporter.Gui, DiscordChatExporter, linux-musl-x64) (push) Blocked by required conditions
main / deploy (DiscordChatExporter.Gui, DiscordChatExporter, linux-x64) (push) Blocked by required conditions
main / deploy (DiscordChatExporter.Gui, DiscordChatExporter, osx-arm64) (push) Blocked by required conditions
main / deploy (DiscordChatExporter.Gui, DiscordChatExporter, osx-x64) (push) Blocked by required conditions
main / deploy (DiscordChatExporter.Gui, DiscordChatExporter, win-arm64) (push) Blocked by required conditions
main / deploy (DiscordChatExporter.Gui, DiscordChatExporter, win-x64) (push) Blocked by required conditions
main / deploy (DiscordChatExporter.Gui, DiscordChatExporter, win-x86) (push) Blocked by required conditions
main / notify (push) Blocked by required conditions
Improve, clean up encryption
2026-02-27 14:57:15 +02:00

103 lines
3.2 KiB
C#

using System;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using DiscordChatExporter.Gui.Utils.Extensions;
namespace DiscordChatExporter.Gui.Services;
public partial class SettingsService
{
private class TokenEncryptionConverter : JsonConverter<string?>
{
private const string Prefix = "enc:";
private static readonly Lazy<byte[]> Key = new(() =>
Rfc2898DeriveBytes.Pbkdf2(
Encoding.UTF8.GetBytes(Environment.TryGetMachineId() ?? string.Empty),
Encoding.UTF8.GetBytes(ThisAssembly.Project.EncryptionSalt),
600_000,
HashAlgorithmName.SHA256,
16
)
);
public override string? Read(
ref Utf8JsonReader reader,
Type typeToConvert,
JsonSerializerOptions options
)
{
var value = reader.GetString();
// No prefix means the token is stored as plain text, which was the case for older
// versions of the application. Load it as is and encrypt it on next save.
if (
string.IsNullOrWhiteSpace(value)
|| !value.StartsWith(Prefix, StringComparison.Ordinal)
)
{
return value;
}
try
{
var encryptedData = Convert.FromHexString(value[Prefix.Length..]);
var tokenData = new byte[encryptedData.AsSpan(28).Length];
// Layout: nonce (12 bytes) | tag (16 bytes) | cipher
using var aes = new AesGcm(Key.Value, 16);
aes.Decrypt(
encryptedData.AsSpan(0, 12),
encryptedData.AsSpan(28),
encryptedData.AsSpan(12, 16),
tokenData
);
return Encoding.UTF8.GetString(tokenData);
}
catch (Exception ex)
when (ex
is FormatException
or CryptographicException
or ArgumentException
or IndexOutOfRangeException
)
{
return null;
}
}
public override void Write(
Utf8JsonWriter writer,
string? value,
JsonSerializerOptions options
)
{
if (string.IsNullOrWhiteSpace(value))
{
writer.WriteNullValue();
return;
}
var tokenData = Encoding.UTF8.GetBytes(value);
var encryptedData = new byte[28 + tokenData.Length];
// Nonce
RandomNumberGenerator.Fill(encryptedData.AsSpan(0, 12));
// Layout: nonce (12 bytes) | tag (16 bytes) | cipher
using var aes = new AesGcm(Key.Value, 16);
aes.Encrypt(
encryptedData.AsSpan(0, 12),
tokenData,
encryptedData.AsSpan(28),
encryptedData.AsSpan(12, 16)
);
writer.WriteStringValue(Prefix + Convert.ToHexStringLower(encryptedData));
}
}
}