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
{
///
/// Header filter AES key, value and User-Agent
///
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";
///
/// Sends https request to the server
///
/// Type of return object
/// host of server
/// controller of request
/// action of request
/// encrypted request, that should be signed and sent
/// keyPair for encryption/decryption/signing(optional)
/// Returns given typed object
public static T? Post(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(json, new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true
});
}
}
catch (Exception ex)
{
Log.Error(ex, "ServiceShared.Https.Request", "Post(string, string, string, EncryptedRequest, KeyPair");
}
return (T?)result;
}
///
/// Gets Public Key of server
///
/// host of server
/// exchange controller of server(default exchange)
/// exchange action of controller(default key)
/// keyPair for encryption/decryption/signing(optional)
/// Returns given typed object
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(json, new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true
});
}
}
catch (Exception ex)
{
Log.Error(ex, "ServiceShared.Https.Request", "GetPublicKey(string, string, string, KeyPair");
}
return result;
}
///
/// Sends https request to the server
///
/// host of server
/// exchange controller of server(default exchange)
/// exchange action of controller(default key)
/// keyPair for encryption/decryption/signing(optional)
/// Returns response as string
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;
}
///
/// Sends https request to the server
///
/// host of server
/// controller of request
/// action of request
/// encrypted request, that should be signed and sent
/// keyPair for encryption/decryption/signing(optional)
/// Returns response as string
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;
}
///
/// Sends https request to the server and does not wait for response
///
/// host of server
/// controller of request
/// action of request
/// encrypted request, that should be signed and sent
/// keyPair for encryption/decryption/signing(optional)
/// Returns response as string
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)");
}
}
///
/// Validates user agent
///
/// User-Agent from header, that should be validated
/// returns true if User-Agent is valid
public static bool ValidUserAgent(string userAgent)
{
return (!string.IsNullOrEmpty(userAgent) && userAgent == TrustedUserAgent);
}
///
/// Validates header hash with AES key
///
/// header hash of client, that should be validated
/// returns true if header hash is valid
public static bool ValidHeaderHash(string headerHash)
{
return (!string.IsNullOrEmpty(headerHash) && AES.Decrypt(headerHash, AES.GetKey(HeaderSecureHash)) == HeaderValueSecureHash);
}
///
/// Returns Header Value Secure Hash for Trusted Response(Signature)
///
///
public static string GeServerHeaderValueSecureHash()
{
return HeaderValueSecureHash;
}
///
/// Returns Header Secure Hash for Trusted Response
///
///
public static string GeServerHash()
{
return AES.Encrypt(HeaderValueSecureHash, AES.GetKey(HeaderSecureHash));
}
}
}