patbef-ServiceOutside/ServiceShared/Https/Request.cs

304 lines
13 KiB
C#
Raw Normal View History

2024-01-29 16:27:34 +01:00
using ServiceShared.Crypto;
using ServiceShared.Models.Request;
using ServiceShared.Models.Response;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Security;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
namespace ServiceShared.Https
{
public static class Request
{
/// <summary>
/// Header filter AES key, value and User-Agent
/// </summary>
internal static readonly string HeaderSecureHash = "3HzKQw/&>*VH^?cAR{Qd5pP~6w(V5%aZ";
internal static readonly string HeaderValueSecureHash = "7*R3P!f:sC4Q8XS:@*J/z:4/sS;V3GnM";
private static readonly string TrustedUserAgent = "BefundApp";
/// <summary>
/// Sends https request to the server
/// </summary>
/// <typeparam name="T">Type of return object</typeparam>
/// <param name="host">host of server</param>
/// <param name="controller">controller of request</param>
/// <param name="action">action of request</param>
/// <param name="request">encrypted request, that should be signed and sent</param>
/// <param name="keyPair">keyPair for encryption/decryption/signing(optional)</param>
/// <returns>Returns given typed object</returns>
public static T? Post<T>(string host, string controller, string action, EncryptedRequest request, KeyPair keyPair = null)
{
object? result = null;
try
{
string json = Post(host, controller, action, request, keyPair);
if(!string.IsNullOrEmpty(json))
{
result = JsonSerializer.Deserialize<T>(json, new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true
});
}
}
catch (Exception ex)
{
Log.Error(ex, "ServiceShared.Https.Request", "Post<T>(string, string, string, EncryptedRequest, KeyPair");
}
return (T?)result;
}
/// <summary>
/// Gets Public Key of server
/// </summary>
/// <param name="host">host of server</param>
/// <param name="controller">exchange controller of server(default exchange)</param>
/// <param name="action">exchange action of controller(default key)</param>
/// <param name="keyPair">keyPair for encryption/decryption/signing(optional)</param>
/// <returns>Returns given typed object</returns>
public static PublicKey GetPublicKey(string host, string controller = "exchange", string action = "key", KeyPair keyPair = null)
{
PublicKey result = null;
try
{
string json = Post(host, controller, action, keyPair);
if (!string.IsNullOrEmpty(json))
{
result = JsonSerializer.Deserialize<PublicKey>(json, new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true
});
}
}
catch (Exception ex)
{
Log.Error(ex, "ServiceShared.Https.Request", "GetPublicKey(string, string, string, KeyPair");
}
return result;
}
/// <summary>
/// Sends https request to the server
/// </summary>
/// <param name="host">host of server</param>
/// <param name="controller">exchange controller of server(default exchange)</param>
/// <param name="action">exchange action of controller(default key)</param>
/// <param name="keyPair">keyPair for encryption/decryption/signing(optional)</param>
/// <returns>Returns response as string</returns>
public static string Post(string host, string controller, string action, KeyPair keyPair = null)
{
string result = null;
try
{
if (keyPair == null)
{
keyPair = Curve25519.GenerateKeyPair();
}
string requestUrl = "https://" + host.Replace("https://", "").Replace("http://", "").TrimEnd('/') + "/" + controller + "/" + action;
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(requestUrl);
string json = JsonSerializer.Serialize(new KeyExchange(), new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true
});
webRequest.Method = "POST";
webRequest.Headers.Add("User-Agent", TrustedUserAgent);
webRequest.Headers.Add("Client-Hash", AES.Encrypt(HeaderValueSecureHash, AES.GetKey(HeaderSecureHash)));
webRequest.Headers.Add("Client-Key", keyPair.PublicKey);
webRequest.Headers.Add("Content-Type", "application/json");
webRequest.ContentType = "application/json";
webRequest.ContentLength = json.Length;
webRequest.ServerCertificateValidationCallback = (sender, cert, chain, sslPolicyErrors) => { return true; };
using (Stream stream = webRequest.GetRequestStream())
{
byte[] data = Encoding.UTF8.GetBytes(json);
stream.Write(data, 0, data.Length);
}
Log.Debug("[REQUEST]: " + json);
WebResponse response = (HttpWebResponse)webRequest.GetResponse();
result = new StreamReader(response.GetResponseStream()).ReadToEnd();
Log.Debug("[RESPONSE]: " + result);
}
catch (Exception ex)
{
Log.Error(ex, "ServiceShared.Https.Request", "Post(string, string, string, KeyPair)");
}
return result;
}
/// <summary>
/// Sends https request to the server
/// </summary>
/// <param name="host">host of server</param>
/// <param name="controller">controller of request</param>
/// <param name="action">action of request</param>
/// <param name="request">encrypted request, that should be signed and sent</param>
/// <param name="keyPair">keyPair for encryption/decryption/signing(optional)</param>
/// <returns>Returns response as string</returns>
public static string Post(string host, string controller, string action, EncryptedRequest request, KeyPair keyPair = null)
{
string result = null;
try
{
if(request != null && !string.IsNullOrEmpty(request.encrypted_content))
{
if (keyPair == null)
{
keyPair = Curve25519.GenerateKeyPair();
}
string requestUrl = "https://" + host.Replace("https://", "").Replace("http://", "").TrimEnd('/') + "/" + controller + "/" + action;
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(requestUrl);
string json = JsonSerializer.Serialize(request, new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true
});
webRequest.Method = "POST";
webRequest.Headers.Add("User-Agent", TrustedUserAgent);
webRequest.Headers.Add("Client-Hash", AES.Encrypt(HeaderValueSecureHash, AES.GetKey(HeaderSecureHash)));
webRequest.Headers.Add("Client-Key", keyPair.PublicKey);
webRequest.Headers.Add("Client-Signature", keyPair.GetSignature((!string.IsNullOrEmpty(request.encrypted_content) ? request.encrypted_content : request.descriptor)));
webRequest.Headers.Add("Client-Signature-Key", keyPair.SigningPublicKey);
webRequest.Headers.Add("Content-Type", "application/json");
webRequest.ContentType = "application/json";
webRequest.ContentLength = json.Length;
webRequest.ServerCertificateValidationCallback = (sender, cert, chain, sslPolicyErrors) => { return true; };
using (Stream stream = webRequest.GetRequestStream())
{
byte[] data = Encoding.UTF8.GetBytes(json);
stream.Write(data, 0, data.Length);
}
Log.Debug("[REQUEST]: " + json);
WebResponse response = (HttpWebResponse)webRequest.GetResponse();
result = new StreamReader(response.GetResponseStream()).ReadToEnd();
Log.Debug("[RESPONSE]: " + result);
}
}
catch (Exception ex)
{
Log.Error(ex, "ServiceShared.Https.Request", "Post(string, string, string, EncryptedRequest, KeyPair)");
}
return result;
}
/// <summary>
/// Sends https request to the server and does not wait for response
/// </summary>
/// <param name="host">host of server</param>
/// <param name="controller">controller of request</param>
/// <param name="action">action of request</param>
/// <param name="request">encrypted request, that should be signed and sent</param>
/// <param name="keyPair">keyPair for encryption/decryption/signing(optional)</param>
/// <returns>Returns response as string</returns>
public static async Task PostWithoutResponse(string host, string controller, string action, EncryptedRequest request, KeyPair keyPair = null)
{
try
{
if (request != null && !string.IsNullOrEmpty(request.encrypted_content))
{
if (keyPair == null)
{
keyPair = Curve25519.GenerateKeyPair();
}
string requestUrl = "https://" + host.Replace("https://", "").Replace("http://", "").TrimEnd('/') + "/" + controller + "/" + action;
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(requestUrl);
string json = JsonSerializer.Serialize(request, new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true
});
webRequest.Method = "POST";
webRequest.Headers.Add("User-Agent", TrustedUserAgent);
webRequest.Headers.Add("Client-Hash", AES.Encrypt(HeaderValueSecureHash, AES.GetKey(HeaderSecureHash)));
webRequest.Headers.Add("Client-Key", keyPair.PublicKey);
webRequest.Headers.Add("Client-Signature", keyPair.GetSignature((!string.IsNullOrEmpty(request.encrypted_content) ? request.encrypted_content : request.descriptor)));
webRequest.Headers.Add("Client-Signature-Key", keyPair.SigningPublicKey);
webRequest.Headers.Add("Content-Type", "application/json");
webRequest.ContentType = "application/json";
webRequest.ContentLength = json.Length;
webRequest.ServerCertificateValidationCallback = (sender, cert, chain, sslPolicyErrors) => { return true; };
using (Stream stream = webRequest.GetRequestStream())
{
byte[] data = Encoding.UTF8.GetBytes(json);
stream.Write(data, 0, data.Length);
stream.Flush();
stream.Close();
webRequest.GetResponseAsync();
}
}
}
catch (Exception ex)
{
Log.Error(ex, "ServiceShared.Https.Request", "PostWithoutResponse(string, string, string, EncryptedRequest, KeyPair)");
}
}
/// <summary>
/// Validates user agent
/// </summary>
/// <param name="userAgent">User-Agent from header, that should be validated</param>
/// <returns>returns true if User-Agent is valid</returns>
public static bool ValidUserAgent(string userAgent)
{
return (!string.IsNullOrEmpty(userAgent) && userAgent == TrustedUserAgent);
}
/// <summary>
/// Validates header hash with AES key
/// </summary>
/// <param name="headerHash">header hash of client, that should be validated</param>
/// <returns>returns true if header hash is valid</returns>
public static bool ValidHeaderHash(string headerHash)
{
return (!string.IsNullOrEmpty(headerHash) && AES.Decrypt(headerHash, AES.GetKey(HeaderSecureHash)) == HeaderValueSecureHash);
}
/// <summary>
/// Returns Header Value Secure Hash for Trusted Response(Signature)
/// </summary>
/// <returns></returns>
public static string GeServerHeaderValueSecureHash()
{
return HeaderValueSecureHash;
}
/// <summary>
/// Returns Header Secure Hash for Trusted Response
/// </summary>
/// <returns></returns>
public static string GeServerHash()
{
return AES.Encrypt(HeaderValueSecureHash, AES.GetKey(HeaderSecureHash));
}
}
}