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
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;
|
|
}
|
|
}
|
|
|
|
}
|