Temporary repo to track my changes on LTS functions app porting
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

317 lines
11 KiB

using Newtonsoft.Json.Linq;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using Azure.Identity;
using Azure.Security.KeyVault.Secrets;
namespace CDP
{
public class Helpers
{
public static byte[] GenerateAES256Key()
{
using (Aes aesAlg = Aes.Create())
{
aesAlg.KeySize = 256;
aesAlg.GenerateKey();
return aesAlg.Key;
}
}
// hashes a string and removes the dashes (-)
public static string HashToHex(string str)
{
using (SHA256 sha256Hash = SHA256.Create())
{
byte[] bytes = sha256Hash.ComputeHash(Encoding.UTF8.GetBytes(str));
return BitConverter.ToString(bytes).Replace("-", string.Empty).ToLower();
}
}
// takes a short hash and converts it to normal hash.
// Circle Auth uses hashes stored as hex...use this to convert to that format.
public static string ConvertShortHashToHex(string shortHash)
{
// Add padding characters ('=') to the short hash if needed
while (shortHash.Length % 4 != 0)
{
shortHash += "=";
}
// Decode the Base64 short hash to bytes
byte[] hashBytes = Convert.FromBase64String(shortHash);
// Convert the bytes to a hexadecimal string
string hexHash = BitConverter.ToString(hashBytes).Replace("-", "").ToLower();
return hexHash;
}
// Generates an AES Key and converts it to base64
public static string GenerateAES256KeyToBase64()
{
return Convert.ToBase64String(GenerateAES256Key());
}
// Generates a guid, removes the - and then converts it to base64
public static string GenerateShortGuid()
{
Guid guid = Guid.NewGuid();
byte[] bytes = guid.ToByteArray();
string shortGuid = Convert.ToBase64String(bytes);
// Remove padding characters from the end of the Base64 string
shortGuid = shortGuid.TrimEnd('=');
return shortGuid;
}
public static Guid LengthenShortGuid(string shortGuid)
{
// Add padding characters to the end of the Base64 string, if needed
while (shortGuid.Length % 4 != 0)
{
shortGuid += "=";
}
// Convert the Base64 string back to bytes
byte[] bytes = Convert.FromBase64String(shortGuid);
// Create a new GUID from the bytes
Guid guid = new Guid(bytes);
return guid;
}
public static bool VerifyData(string originalMessage, string signedMessage)
{
bool success = false;
using (var rsa = new RSACryptoServiceProvider())
{
var encoder = new UTF8Encoding();
byte[] bytesToVerify = encoder.GetBytes(originalMessage);
byte[] signedBytes = Convert.FromBase64String(signedMessage);
try
{
rsa.FromXmlString(Constants.PublicKey);
SHA512Managed Hash = new SHA512Managed();
byte[] hashedData = Hash.ComputeHash(signedBytes);
success = rsa.VerifyData(bytesToVerify, CryptoConfig.MapNameToOID("SHA512"), signedBytes);
}
catch (CryptographicException e)
{
Console.WriteLine(e.Message);
}
finally
{
rsa.PersistKeyInCsp = false;
}
}
return success;
}
public static string ComputeSignature(string stringToSign, string secret)
{
using (var hmacsha256 = new HMACSHA256(System.Text.ASCIIEncoding.UTF8.GetBytes(secret)))
{
var bytes = Encoding.ASCII.GetBytes(stringToSign);
var hashedBytes = hmacsha256.ComputeHash(bytes);
return Convert.ToBase64String(hashedBytes);
}
}
public static async Task<dynamic> GetSession(string sessionId)
{
string toSign = string.Format($"?s={sessionId}");
string sig = Helpers.ComputeSignature(toSign, Constants.CDPWriteKey);
string URL = string.Format($"https://circleauth.gocircle.ai/api/session/{toSign}&signature={sig}");
try
{
HttpClient client = new HttpClient();
client.Timeout = new TimeSpan(0, 1, 0, 0);
client.DefaultRequestHeaders.Add("x-ua-appKey", Constants.CDPAppKey);
var response = await client.GetAsync(URL);
if (response.StatusCode == System.Net.HttpStatusCode.OK)
{
string responseString = await response.Content.ReadAsStringAsync();
dynamic obj = JObject.Parse(responseString);
dynamic data = obj.data;
return data;
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
return null;
}
public static async Task<Boolean> ExpireSession(string sessionId, string userId)
{
try
{
var dataObj = new { sessionID = sessionId, userID = userId };
var sig = Helpers.ComputeSignature(JsonConvert.SerializeObject(dataObj), Constants.CDPWriteKey);
var obj = new { data = dataObj, signature = sig };
HttpClient client = new HttpClient();
client.Timeout = new TimeSpan(0, 1, 0, 0);
client.DefaultRequestHeaders.Add("x-ua-appKey", Constants.CDPAppKey);
var content = new StringContent(JsonConvert.SerializeObject(obj), Encoding.UTF8, "application/json");
var r = client.PostAsync("https://circleaccess.circlesecurity.ai/api/user/session/expire", content).Result;
return r.StatusCode == HttpStatusCode.OK;
}
catch (Exception e)
{
Console.WriteLine(e);
}
return false;
}
/// <summary>
/// this is the HASH that Circle Auth likes, it's just a SHA265 in hex.
/// </summary>
public static string HashText(string rawData)
{
try
{
// Create a SHA256
using SHA256 sha256Hash = SHA256.Create();
byte[] bytes = sha256Hash.ComputeHash(Encoding.UTF8.GetBytes(rawData));
StringBuilder builder = new();
for (int i = 0; i < bytes.Length; i++)
{
builder.Append(bytes[i].ToString("x2"));
}
return builder.ToString();
}
catch (Exception ex)
{
return null;
}
}
public static string HashAndShortenText(string text)
{
// Hash the email address using SHA-256
using (SHA256 sha256 = SHA256.Create())
{
byte[] hashBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(text));
string shortHash = Convert.ToBase64String(hashBytes);
// make the short hash URL friendly
shortHash = shortHash.Replace("+", "-").Replace("/", "_");
// Remove padding characters from the end of the Base64 string
shortHash = shortHash.TrimEnd('=');
return shortHash;
}
}
public static async Task<SingleLogin> CreateSession(string customerAppKey, string returnURL, string payloadJson, string webHook = "")
{
var client = new HttpClient();
// wacky hack since I can't declare anonymous variables without initializing them
var payloadObject = new
{
Test = "123"
};
var dataObj = new
{
payload = payloadJson,
customerAppKey = customerAppKey,
customID = "blahORama",
returnUrl = returnURL,
mobileUrl = returnURL,
webhookUrl = webHook
};
var sig = Helpers.ComputeSignature(JsonConvert.SerializeObject(dataObj), Constants.CDPWriteKey);
var obj = new { data = dataObj, signature = sig };
string json = JsonConvert.SerializeObject(obj);
client.DefaultRequestHeaders.Add("x-ua-appKey", Constants.CDPAppKey);
HttpContent c = new StringContent(json, Encoding.UTF8, "application/json");
var response = await client.PostAsync(new Uri("https://circleaccess.circlesecurity.ai/api/single/create"), c);
SingleLogin sl = new SingleLogin();
if (response.StatusCode == System.Net.HttpStatusCode.OK)
{
string body = response.Content.ReadAsStringAsync().Result; //right!
dynamic stuff = JObject.Parse(body);
sl.QRCodeUrl = stuff.data.qrcode.ToString();
sl.LoginId = stuff.data.singleLoginID.ToString();
return sl;
}
return null;
}
}
public class KeyVaultService
{
private readonly string _keyVaultUrl;
public KeyVaultService(string keyVaultUrl)
{
_keyVaultUrl = keyVaultUrl;
}
public async Task SetSecretAsync(string secretName, string secretValue)
{
#if DEBUG
var client = new SecretClient(new Uri(_keyVaultUrl), new VisualStudioCredential());
#else
var client = new SecretClient(new Uri(_keyVaultUrl), new DefaultAzureCredential());
#endif
// Set the secret in the Key Vault
await client.SetSecretAsync(secretName, secretValue);
}
public async Task<string> GetSecretAsync(string secretName)
{
#if DEBUG
var client = new SecretClient(new Uri(_keyVaultUrl), new VisualStudioCredential());
#else
var client = new SecretClient(new Uri(_keyVaultUrl), new DefaultAzureCredential());
#endif
// Set the secret in the Key Vault
KeyVaultSecret kvs = await client.GetSecretAsync(secretName);
return kvs.Value;
}
}
public class SingleLogin
{
public string QRCodeUrl { get; set; }
public string LoginId { get; set; }
public SingleLogin()
{
}
public override string ToString()
{
return QRCodeUrl;
}
}
}