Retire legacy implementations and flatten managed layout
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using Org.BouncyCastle.Crypto.Digests;
|
||||
using Voicecat.V1;
|
||||
|
||||
namespace VoiceCat.Server.Data;
|
||||
|
||||
public sealed partial class AccountStore
|
||||
{
|
||||
private static byte[] ChannelDigest(string password, byte[] salt)
|
||||
{
|
||||
var digest = new Blake2bDigest(salt, 32, null, null);
|
||||
byte[] bytes = Encoding.UTF8.GetBytes(password);
|
||||
byte[] hash = new byte[32];
|
||||
try { digest.BlockUpdate(bytes, 0, bytes.Length); digest.DoFinal(hash, 0); return hash; }
|
||||
finally { CryptographicOperations.ZeroMemory(bytes); }
|
||||
}
|
||||
|
||||
public bool CheckChannelPassword(uint id, string password)
|
||||
{
|
||||
using var connection = Open();
|
||||
using var command = connection.CreateCommand();
|
||||
command.CommandText = "SELECT password_hash FROM channels WHERE id=$id";
|
||||
command.Parameters.AddWithValue("$id", id);
|
||||
if (command.ExecuteScalar() is not string stored) return false;
|
||||
if (stored.Length == 0) return true;
|
||||
if (stored.Length != 97 || stored[32] != ':') return false;
|
||||
try
|
||||
{
|
||||
byte[] salt = Convert.FromHexString(stored[..32]);
|
||||
return CryptographicOperations.FixedTimeEquals(ChannelDigest(password, salt), Convert.FromHexString(stored[33..]));
|
||||
}
|
||||
catch (FormatException) { return false; }
|
||||
}
|
||||
|
||||
internal Channel SaveChannel(Channel channel, string password, bool create)
|
||||
{
|
||||
using var connection = Open();
|
||||
using var command = connection.CreateCommand();
|
||||
string hash = "";
|
||||
if (password.Length != 0)
|
||||
{
|
||||
byte[] salt = RandomNumberGenerator.GetBytes(16);
|
||||
hash = Convert.ToHexString(salt).ToLowerInvariant() + ":" + Convert.ToHexString(ChannelDigest(password, salt)).ToLowerInvariant();
|
||||
}
|
||||
string[] columns = ["parent_id", "name", "topic", "max_users", "type", "sort_order", "audio_codec", "audio_mode", "audio_sample_rate", "audio_bitrate_bps", "audio_frame_ms", "audio_application", "audio_fec", "audio_expected_packet_loss", "audio_dtx", "audio_complexity"];
|
||||
var a = channel.Audio;
|
||||
object[] values = [channel.ParentId, channel.Name, channel.Topic, channel.MaxUsers, (int)channel.Type, channel.Order, a.Codec, (int)a.Mode, a.SampleRate, a.BitrateBps, a.FrameMs, (int)a.Application, a.Fec, a.ExpectedPacketLoss, a.Dtx, a.Complexity];
|
||||
for (int i = 0; i < columns.Length; i++) command.Parameters.AddWithValue("$" + columns[i], values[i]);
|
||||
command.Parameters.AddWithValue("$hash", hash);
|
||||
command.Parameters.AddWithValue("$id", channel.Id);
|
||||
command.CommandText = create
|
||||
? $"INSERT INTO channels ({string.Join(',', columns)},password_hash) VALUES ({string.Join(',', columns.Select(c => "$" + c))},$hash) RETURNING id"
|
||||
: $"UPDATE channels SET {string.Join(',', columns.Select(c => c + "=$" + c))},password_hash=CASE WHEN $hash='' THEN password_hash ELSE $hash END WHERE id=$id RETURNING id";
|
||||
var saved = channel.Clone();
|
||||
saved.Id = checked((uint)(long)(command.ExecuteScalar() ?? throw new InvalidDataException("Channel not found.")));
|
||||
saved.PasswordProtected = hash.Length != 0 || !create && CheckChannelPasswordPresent(saved.Id);
|
||||
return saved;
|
||||
}
|
||||
|
||||
private bool CheckChannelPasswordPresent(uint id)
|
||||
{
|
||||
using var connection = Open();
|
||||
using var command = connection.CreateCommand();
|
||||
command.CommandText = "SELECT length(password_hash)>0 FROM channels WHERE id=$id";
|
||||
command.Parameters.AddWithValue("$id", id);
|
||||
return (long)command.ExecuteScalar()! != 0;
|
||||
}
|
||||
|
||||
internal void DeleteChannel(uint id)
|
||||
{
|
||||
using var connection = Open();
|
||||
using var command = connection.CreateCommand();
|
||||
command.CommandText = "DELETE FROM channels WHERE id=$id";
|
||||
command.Parameters.AddWithValue("$id", id);
|
||||
command.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user