diff --git a/SimpleHttpServer/IAuthorizer.cs b/SimpleHttpServer/IAuthorizer.cs deleted file mode 100644 index 4720221..0000000 --- a/SimpleHttpServer/IAuthorizer.cs +++ /dev/null @@ -1,7 +0,0 @@ -using System.Net; - -namespace SimpleHttpServer; - -public interface IAuthorizer { - public abstract (bool auth, object? data) IsAuthenticated(HttpListenerContext contect); -} diff --git a/SimpleHttpServer/Internal/DefaultAuthorizer.cs b/SimpleHttpServer/Internal/DefaultAuthorizer.cs deleted file mode 100644 index 62a27b6..0000000 --- a/SimpleHttpServer/Internal/DefaultAuthorizer.cs +++ /dev/null @@ -1,7 +0,0 @@ -using System.Net; - -namespace SimpleHttpServer.Internal; - -public sealed class DefaultAuthorizer : IAuthorizer { - public (bool auth, object? data) IsAuthenticated(HttpListenerContext contect) => (true, null); -} diff --git a/SimpleHttpServer/Internal/HttpEndpointHandler.cs b/SimpleHttpServer/Internal/HttpEndpointHandler.cs index 1f3396d..c88e5d7 100644 --- a/SimpleHttpServer/Internal/HttpEndpointHandler.cs +++ b/SimpleHttpServer/Internal/HttpEndpointHandler.cs @@ -1,73 +1,73 @@ -using Newtonsoft.Json; -using System.Collections; -using System.Net; -using System.Reflection; +//using Newtonsoft.Json; +//using System.Collections; +//using System.Net; +//using System.Reflection; -namespace SimpleHttpServer.Internal; +//namespace SimpleHttpServer.Internal; -internal class HttpEndpointHandler { - private static readonly DefaultAuthorizer defaultAuth = new(); +//internal class HttpEndpointHandler { +// private static readonly DefaultAuthorizer defaultAuth = new(); - private readonly IAuthorizer auth; - private readonly MethodInfo handler; - private readonly Dictionary @params; - private readonly Func errorPageBuilder; +// private readonly IAuthorizer auth; +// private readonly MethodInfo handler; +// private readonly Dictionary @params; +// private readonly Func errorPageBuilder; - public HttpEndpointHandler() { - auth = defaultAuth; - } +// public HttpEndpointHandler() { +// auth = defaultAuth; +// } - public HttpEndpointHandler(IAuthorizer auth) { +// public HttpEndpointHandler(IAuthorizer auth) { - } +// } - public virtual void Handle(HttpListenerContext ctx) { - try { - var (isAuth, authData) = auth.IsAuthenticated(ctx); - if (!isAuth) { - throw new HttpHandlingException(401, "Authorization required!"); - } +// public virtual void Handle(HttpListenerContext ctx) { +// try { +// var (isAuth, authData) = auth.IsAuthenticated(ctx); +// if (!isAuth) { +// throw new HttpHandlingException(401, "Authorization required!"); +// } - // collect parameters - var invokeParams = new object?[@params.Count + 1]; - var set = new BitArray(@params.Count); - invokeParams[0] = ctx; +// // collect parameters +// var invokeParams = new object?[@params.Count + 1]; +// var set = new BitArray(@params.Count); +// invokeParams[0] = ctx; - // read pparams +// // read pparams - // read qparams - var qst = ctx.Request.QueryString; - foreach (var qelem in ctx.Request.QueryString.AllKeys) { - if (@params.ContainsKey(qelem!)) { - var (pindex, type, isPParam) = @params[qelem!]; - if (type == typeof(string)) { - invokeParams[pindex] = ctx.Request.QueryString[qelem!]; - set.Set(pindex - 1, true); - } else { - var elem = JsonConvert.DeserializeObject(ctx.Request.QueryString[qelem!]!, type); - if (elem != null) { - invokeParams[pindex] = elem; - set.Set(pindex - 1, true); - } - } - } - } +// // read qparams +// var qst = ctx.Request.QueryString; +// foreach (var qelem in ctx.Request.QueryString.AllKeys) { +// if (@params.ContainsKey(qelem!)) { +// var (pindex, type, isPParam) = @params[qelem!]; +// if (type == typeof(string)) { +// invokeParams[pindex] = ctx.Request.QueryString[qelem!]; +// set.Set(pindex - 1, true); +// } else { +// var elem = JsonConvert.DeserializeObject(ctx.Request.QueryString[qelem!]!, type); +// if (elem != null) { +// invokeParams[pindex] = elem; +// set.Set(pindex - 1, true); +// } +// } +// } +// } - // fill with defaults - foreach (var p in @params) { - if (!set.Get(p.Value.pindex)) { - invokeParams[p.Value.pindex] = p.Value.type.IsValueType ? Activator.CreateInstance(p.Value.type) : null; - } - } +// // fill with defaults +// foreach (var p in @params) { +// if (!set.Get(p.Value.pindex)) { +// invokeParams[p.Value.pindex] = p.Value.type.IsValueType ? Activator.CreateInstance(p.Value.type) : null; +// } +// } - var builder = handler.Invoke(null, invokeParams) as HttpResponseBuilder; - builder!.SendResponse(ctx.Response); - } catch (Exception e) { - if (e is TargetInvocationException tex) { - e = tex.InnerException!; - } - errorPageBuilder(e).SendResponse(ctx.Response); - } - } -} +// var builder = handler.Invoke(null, invokeParams) as HttpResponseBuilder; +// builder!.SendResponse(ctx.Response); +// } catch (Exception e) { +// if (e is TargetInvocationException tex) { +// e = tex.InnerException!; +// } +// errorPageBuilder(e).SendResponse(ctx.Response); +// } +// } +//} diff --git a/SimpleHttpServer/Login/LoginProvider.cs b/SimpleHttpServer/Login/LoginProvider.cs index e5b9f81..dd95cce 100644 --- a/SimpleHttpServer/Login/LoginProvider.cs +++ b/SimpleHttpServer/Login/LoginProvider.cs @@ -1,245 +1,245 @@ -using Newtonsoft.Json; -using System.Diagnostics.CodeAnalysis; -using System.Security.Cryptography; -using System.Text; +//using Newtonsoft.Json; +//using System.Diagnostics.CodeAnalysis; +//using System.Security.Cryptography; +//using System.Text; -namespace SimpleHttpServer.Login; +//namespace SimpleHttpServer.Login; -internal struct SerialLoginData { - public string passwordSalt; - public string extraDataSalt; - public string pwd; - public string extraData; +//internal struct SerialLoginData { +// public string passwordSalt; +// public string extraDataSalt; +// public string pwd; +// public string extraData; - public LoginData ToPlainData() { - return new LoginData { - passwordSalt = Convert.FromBase64String(passwordSalt), - extraDataSalt = Convert.FromBase64String(extraDataSalt) - }; - } -} +// public LoginData ToPlainData() { +// return new LoginData { +// passwordSalt = Convert.FromBase64String(passwordSalt), +// extraDataSalt = Convert.FromBase64String(extraDataSalt) +// }; +// } +//} -internal struct LoginData { - public byte[] passwordSalt; - public byte[] extraDataSalt; - public byte[] passwordHash; - public byte[] encryptedExtraData; +//internal struct LoginData { +// public byte[] passwordSalt; +// public byte[] extraDataSalt; +// public byte[] passwordHash; +// public byte[] encryptedExtraData; - public SerialLoginData ToSerial() { - return new SerialLoginData { - passwordSalt = Convert.ToBase64String(passwordSalt), - extraDataSalt = Convert.ToBase64String(extraDataSalt), - pwd = Convert.ToBase64String(passwordHash), - extraData = Convert.ToBase64String(encryptedExtraData) - }; - } -} +// public SerialLoginData ToSerial() { +// return new SerialLoginData { +// passwordSalt = Convert.ToBase64String(passwordSalt), +// extraDataSalt = Convert.ToBase64String(extraDataSalt), +// pwd = Convert.ToBase64String(passwordHash), +// extraData = Convert.ToBase64String(encryptedExtraData) +// }; +// } +//} -internal struct LoginDataProviderConfig { +//internal struct LoginDataProviderConfig { - /// - /// Size of the password salt and the extradata salt. So each salt will be of size . - /// - public int SALT_SIZE = 32; - public int KEY_LENGTH = 256 / 8; - public int PBKDF2_ITERATIONS = 600_000; +// /// +// /// Size of the password salt and the extradata salt. So each salt will be of size . +// /// +// public int SALT_SIZE = 32; +// public int KEY_LENGTH = 256 / 8; +// public int PBKDF2_ITERATIONS = 600_000; - public LoginDataProviderConfig() { } -} +// public LoginDataProviderConfig() { } +//} -public class LoginProvider { +//public class LoginProvider { - private static readonly Func JsonSerialize = t => Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(t)); - private static readonly Func JsonDeserialize = b => JsonConvert.DeserializeObject(Encoding.UTF8.GetString(b))!; +// private static readonly Func JsonSerialize = t => Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(t)); +// private static readonly Func JsonDeserialize = b => JsonConvert.DeserializeObject(Encoding.UTF8.GetString(b))!; - [ThreadStatic] - private static SHA256? _sha256PerThread; - private static SHA256 Sha256PerThread { get => _sha256PerThread ??= SHA256.Create(); } +// [ThreadStatic] +// private static SHA256? _sha256PerThread; +// private static SHA256 Sha256PerThread { get => _sha256PerThread ??= SHA256.Create(); } - private readonly LoginDataProviderConfig config; - private readonly ReaderWriterLockSlim ldLock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion); - private readonly string ldPath; - private readonly Dictionary loginDatas; +// private readonly LoginDataProviderConfig config; +// private readonly ReaderWriterLockSlim ldLock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion); +// private readonly string ldPath; +// private readonly Dictionary loginDatas; - private Func DataSerializer = JsonSerialize; - private Func DataDeserializer = JsonDeserialize; - public void SetDataSerializers(Func serializer, Func deserializer) { - DataSerializer = serializer ?? JsonSerialize; - DataDeserializer = deserializer ?? JsonDeserialize; - } +// private Func DataSerializer = JsonSerialize; +// private Func DataDeserializer = JsonDeserialize; +// public void SetDataSerializers(Func serializer, Func deserializer) { +// DataSerializer = serializer ?? JsonSerialize; +// DataDeserializer = deserializer ?? JsonDeserialize; +// } - public LoginProvider(string ldPath, string confPath) { - this.ldPath = ldPath; - loginDatas = LoadLoginDatas(ldPath); - config = LoadLoginProviderConfig(confPath); - } +// public LoginProvider(string ldPath, string confPath) { +// this.ldPath = ldPath; +// loginDatas = LoadLoginDatas(ldPath); +// config = LoadLoginProviderConfig(confPath); +// } - private static Dictionary LoadLoginDatas(string path) { - Dictionary tempData; - if (!File.Exists(path)) { - File.WriteAllText(path, "{}", Encoding.UTF8); - tempData = new(); - } else { - tempData = JsonConvert.DeserializeObject>(File.ReadAllText(path))!; - if (tempData == null) { - throw new InvalidDataException($"could not read login data from file {path}"); - } - } - var ld = new Dictionary(); - foreach (var pair in tempData) { - ld.Add(pair.Key, pair.Value.ToPlainData()); - } - return ld; - } +// private static Dictionary LoadLoginDatas(string path) { +// Dictionary tempData; +// if (!File.Exists(path)) { +// File.WriteAllText(path, "{}", Encoding.UTF8); +// tempData = new(); +// } else { +// tempData = JsonConvert.DeserializeObject>(File.ReadAllText(path))!; +// if (tempData == null) { +// throw new InvalidDataException($"could not read login data from file {path}"); +// } +// } +// var ld = new Dictionary(); +// foreach (var pair in tempData) { +// ld.Add(pair.Key, pair.Value.ToPlainData()); +// } +// return ld; +// } - private void SaveLoginData() { - var serial = new Dictionary(); - ldLock.EnterWriteLock(); - try { - foreach (var pair in loginDatas) { - serial.Add(pair.Key, pair.Value.ToSerial()); - } - } finally { - ldLock.ExitWriteLock(); - } - File.WriteAllText(ldPath, JsonConvert.SerializeObject(serial)); - } +// private void SaveLoginData() { +// var serial = new Dictionary(); +// ldLock.EnterWriteLock(); +// try { +// foreach (var pair in loginDatas) { +// serial.Add(pair.Key, pair.Value.ToSerial()); +// } +// } finally { +// ldLock.ExitWriteLock(); +// } +// File.WriteAllText(ldPath, JsonConvert.SerializeObject(serial)); +// } - private static LoginDataProviderConfig LoadLoginProviderConfig(string path) { - if (!File.Exists(path)) { - var conf = new LoginDataProviderConfig(); - File.WriteAllText(path, JsonConvert.SerializeObject(conf)); - return conf; - } - return JsonConvert.DeserializeObject(File.ReadAllText(path)); - } +// private static LoginDataProviderConfig LoadLoginProviderConfig(string path) { +// if (!File.Exists(path)) { +// var conf = new LoginDataProviderConfig(); +// File.WriteAllText(path, JsonConvert.SerializeObject(conf)); +// return conf; +// } +// return JsonConvert.DeserializeObject(File.ReadAllText(path)); +// } - public bool AddUser(string username, string password, TExtraData additional) { - ldLock.EnterWriteLock(); - try { - if (loginDatas.ContainsKey(username)) { - return false; - } - var passwordSalt = RandomNumberGenerator.GetBytes(config.SALT_SIZE); - var extraDataSalt = RandomNumberGenerator.GetBytes(config.SALT_SIZE); - LoginData ld = new LoginData() { - passwordSalt = passwordSalt, - extraDataSalt = extraDataSalt, - passwordHash = ComputeSaltedSha256Hash(password, passwordSalt), - encryptedExtraData = EncryptExtraData(password, extraDataSalt, additional), - }; - loginDatas.Add(username, ld); - SaveLoginData(); - } finally { - ldLock.ExitWriteLock(); - } - return true; - } +// public bool AddUser(string username, string password, TExtraData additional) { +// ldLock.EnterWriteLock(); +// try { +// if (loginDatas.ContainsKey(username)) { +// return false; +// } +// var passwordSalt = RandomNumberGenerator.GetBytes(config.SALT_SIZE); +// var extraDataSalt = RandomNumberGenerator.GetBytes(config.SALT_SIZE); +// LoginData ld = new LoginData() { +// passwordSalt = passwordSalt, +// extraDataSalt = extraDataSalt, +// passwordHash = ComputeSaltedSha256Hash(password, passwordSalt), +// encryptedExtraData = EncryptExtraData(password, extraDataSalt, additional), +// }; +// loginDatas.Add(username, ld); +// SaveLoginData(); +// } finally { +// ldLock.ExitWriteLock(); +// } +// return true; +// } - public bool RemoveUser(string username) { - ldLock.EnterWriteLock(); - try { - var removed = loginDatas.Remove(username); - if (removed) { - SaveLoginData(); - } - return removed; - } finally { - ldLock.ExitWriteLock(); - } - } +// public bool RemoveUser(string username) { +// ldLock.EnterWriteLock(); +// try { +// var removed = loginDatas.Remove(username); +// if (removed) { +// SaveLoginData(); +// } +// return removed; +// } finally { +// ldLock.ExitWriteLock(); +// } +// } - public bool ModifyUser(string username, string newPassword, TExtraData newExtraData) { - ldLock.EnterWriteLock(); - try { - if (!loginDatas.ContainsKey(username)) { - return false; - } - loginDatas.Remove(username, out var data); - data.passwordHash = ComputeSaltedSha256Hash(newPassword, data.passwordSalt); - data.encryptedExtraData = EncryptExtraData(newPassword, data.extraDataSalt, newExtraData); - loginDatas.Add(username, data); - SaveLoginData(); - } finally { - ldLock.ExitWriteLock(); - } - return true; - } +// public bool ModifyUser(string username, string newPassword, TExtraData newExtraData) { +// ldLock.EnterWriteLock(); +// try { +// if (!loginDatas.ContainsKey(username)) { +// return false; +// } +// loginDatas.Remove(username, out var data); +// data.passwordHash = ComputeSaltedSha256Hash(newPassword, data.passwordSalt); +// data.encryptedExtraData = EncryptExtraData(newPassword, data.extraDataSalt, newExtraData); +// loginDatas.Add(username, data); +// SaveLoginData(); +// } finally { +// ldLock.ExitWriteLock(); +// } +// return true; +// } - public bool TryAuthenticate(string username, string password, [MaybeNullWhen(false)] out TExtraData extraData) { - LoginData data; - ldLock.EnterReadLock(); - try { - if (!loginDatas.TryGetValue(username, out data)) { - extraData = default; - return false; - } - } finally { - ldLock.ExitReadLock(); - } - var hash = ComputeSaltedSha256Hash(password, data.passwordSalt); - if (!hash.SequenceEqual(data.passwordHash)) { - extraData = default; - return false; - } - extraData = DecryptExtraData(password, data.extraDataSalt, data.encryptedExtraData); - return true; - } +// public bool TryAuthenticate(string username, string password, [MaybeNullWhen(false)] out TExtraData extraData) { +// LoginData data; +// ldLock.EnterReadLock(); +// try { +// if (!loginDatas.TryGetValue(username, out data)) { +// extraData = default; +// return false; +// } +// } finally { +// ldLock.ExitReadLock(); +// } +// var hash = ComputeSaltedSha256Hash(password, data.passwordSalt); +// if (!hash.SequenceEqual(data.passwordHash)) { +// extraData = default; +// return false; +// } +// extraData = DecryptExtraData(password, data.extraDataSalt, data.encryptedExtraData); +// return true; +// } - /// - /// Threadsafe as the SHA256 instance () is per thread. - /// - /// - /// - /// - private static byte[] ComputeSaltedSha256Hash(string data, byte[] salt) { - var dataBytes = Encoding.UTF8.GetBytes(data); - var buf = new byte[data.Length + salt.Length]; - Buffer.BlockCopy(dataBytes, 0, buf, 0, dataBytes.Length); - Buffer.BlockCopy(salt, 0, buf, dataBytes.Length, salt.Length); - return Sha256PerThread.ComputeHash(buf); - } +// /// +// /// Threadsafe as the SHA256 instance () is per thread. +// /// +// /// +// /// +// /// +// private static byte[] ComputeSaltedSha256Hash(string data, byte[] salt) { +// var dataBytes = Encoding.UTF8.GetBytes(data); +// var buf = new byte[data.Length + salt.Length]; +// Buffer.BlockCopy(dataBytes, 0, buf, 0, dataBytes.Length); +// Buffer.BlockCopy(salt, 0, buf, dataBytes.Length, salt.Length); +// return Sha256PerThread.ComputeHash(buf); +// } - private byte[] EncryptExtraData(string pwd, byte[] salt, TExtraData extraData) { - var pbkdf2 = new Rfc2898DeriveBytes(Encoding.UTF8.GetBytes(pwd), salt, config.PBKDF2_ITERATIONS, HashAlgorithmName.SHA256); - var key = pbkdf2.GetBytes(config.KEY_LENGTH / 8); +// private byte[] EncryptExtraData(string pwd, byte[] salt, TExtraData extraData) { +// var pbkdf2 = new Rfc2898DeriveBytes(Encoding.UTF8.GetBytes(pwd), salt, config.PBKDF2_ITERATIONS, HashAlgorithmName.SHA256); +// var key = pbkdf2.GetBytes(config.KEY_LENGTH / 8); - var plainBytes = DataSerializer(extraData); - using var aes = Aes.Create(); - aes.KeySize = config.KEY_LENGTH; - aes.Key = key; - aes.Mode = CipherMode.CBC; - aes.Padding = PaddingMode.PKCS7; - ICryptoTransform encryptor = aes.CreateEncryptor(aes.Key, aes.IV); - byte[] cipherBytes = encryptor.TransformFinalBlock(plainBytes, 0, plainBytes.Length); +// var plainBytes = DataSerializer(extraData); +// using var aes = Aes.Create(); +// aes.KeySize = config.KEY_LENGTH; +// aes.Key = key; +// aes.Mode = CipherMode.CBC; +// aes.Padding = PaddingMode.PKCS7; +// ICryptoTransform encryptor = aes.CreateEncryptor(aes.Key, aes.IV); +// byte[] cipherBytes = encryptor.TransformFinalBlock(plainBytes, 0, plainBytes.Length); - var encryptedBytes = new byte[aes.IV.Length + cipherBytes.Length]; - Array.Copy(aes.IV, 0, encryptedBytes, 0, aes.IV.Length); - Array.Copy(cipherBytes, 0, encryptedBytes, aes.IV.Length, cipherBytes.Length); +// var encryptedBytes = new byte[aes.IV.Length + cipherBytes.Length]; +// Array.Copy(aes.IV, 0, encryptedBytes, 0, aes.IV.Length); +// Array.Copy(cipherBytes, 0, encryptedBytes, aes.IV.Length, cipherBytes.Length); - return encryptedBytes; - } +// return encryptedBytes; +// } - private TExtraData DecryptExtraData(string pwd, byte[] salt, byte[] encryptedData) { - var pbkdf2 = new Rfc2898DeriveBytes(Encoding.UTF8.GetBytes(pwd), salt, config.PBKDF2_ITERATIONS, HashAlgorithmName.SHA256); - var key = pbkdf2.GetBytes(config.KEY_LENGTH / 8); +// private TExtraData DecryptExtraData(string pwd, byte[] salt, byte[] encryptedData) { +// var pbkdf2 = new Rfc2898DeriveBytes(Encoding.UTF8.GetBytes(pwd), salt, config.PBKDF2_ITERATIONS, HashAlgorithmName.SHA256); +// var key = pbkdf2.GetBytes(config.KEY_LENGTH / 8); - using var aes = Aes.Create(); - aes.KeySize = config.KEY_LENGTH; - aes.Key = key; - aes.Mode = CipherMode.CBC; - aes.Padding = PaddingMode.PKCS7; - var iv = new byte[aes.BlockSize / 8]; - var cipherBytes = new byte[encryptedData.Length - iv.Length]; +// using var aes = Aes.Create(); +// aes.KeySize = config.KEY_LENGTH; +// aes.Key = key; +// aes.Mode = CipherMode.CBC; +// aes.Padding = PaddingMode.PKCS7; +// var iv = new byte[aes.BlockSize / 8]; +// var cipherBytes = new byte[encryptedData.Length - iv.Length]; - Array.Copy(encryptedData, 0, iv, 0, iv.Length); - Array.Copy(encryptedData, iv.Length, cipherBytes, 0, cipherBytes.Length); +// Array.Copy(encryptedData, 0, iv, 0, iv.Length); +// Array.Copy(encryptedData, iv.Length, cipherBytes, 0, cipherBytes.Length); - aes.IV = iv; - ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, aes.IV); - byte[] plainBytes = decryptor.TransformFinalBlock(cipherBytes, 0, cipherBytes.Length); +// aes.IV = iv; +// ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, aes.IV); +// byte[] plainBytes = decryptor.TransformFinalBlock(cipherBytes, 0, cipherBytes.Length); - return DataDeserializer(plainBytes); - } -} +// return DataDeserializer(plainBytes); +// } +//} diff --git a/SimpleHttpServer/Types/RequestContext.cs b/SimpleHttpServer/Types/RequestContext.cs index fb4c0a6..1fd3690 100644 --- a/SimpleHttpServer/Types/RequestContext.cs +++ b/SimpleHttpServer/Types/RequestContext.cs @@ -19,9 +19,11 @@ public class RequestContext : IDisposable { /// public TextWriter RespWriter => respWriter ??= TextWriter.Synchronized(new StreamWriter(ListenerContext.Response.OutputStream) { NewLine = "\n" }); +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. public RequestContext(HttpListenerContext listenerContext) { ListenerContext = listenerContext; } +#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. public async Task WriteLineToRespAsync(string resp) => await RespWriter.WriteLineAsync(resp); public async Task WriteToRespAsync(string resp) => await RespWriter.WriteAsync(resp);