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

  1. using Newtonsoft.Json.Linq;
  2. using Newtonsoft.Json;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Linq;
  6. using System.Net;
  7. using System.Security.Cryptography;
  8. using System.Text;
  9. using System.Threading.Tasks;
  10. using Azure.Identity;
  11. using Azure.Security.KeyVault.Secrets;
  12. namespace CDP
  13. {
  14. public class Helpers
  15. {
  16. public static byte[] GenerateAES256Key()
  17. {
  18. using (Aes aesAlg = Aes.Create())
  19. {
  20. aesAlg.KeySize = 256;
  21. aesAlg.GenerateKey();
  22. return aesAlg.Key;
  23. }
  24. }
  25. // hashes a string and removes the dashes (-)
  26. public static string HashToHex(string str)
  27. {
  28. using (SHA256 sha256Hash = SHA256.Create())
  29. {
  30. byte[] bytes = sha256Hash.ComputeHash(Encoding.UTF8.GetBytes(str));
  31. return BitConverter.ToString(bytes).Replace("-", string.Empty).ToLower();
  32. }
  33. }
  34. // takes a short hash and converts it to normal hash.
  35. // Circle Auth uses hashes stored as hex...use this to convert to that format.
  36. public static string ConvertShortHashToHex(string shortHash)
  37. {
  38. // Add padding characters ('=') to the short hash if needed
  39. while (shortHash.Length % 4 != 0)
  40. {
  41. shortHash += "=";
  42. }
  43. // Decode the Base64 short hash to bytes
  44. byte[] hashBytes = Convert.FromBase64String(shortHash);
  45. // Convert the bytes to a hexadecimal string
  46. string hexHash = BitConverter.ToString(hashBytes).Replace("-", "").ToLower();
  47. return hexHash;
  48. }
  49. // Generates an AES Key and converts it to base64
  50. public static string GenerateAES256KeyToBase64()
  51. {
  52. return Convert.ToBase64String(GenerateAES256Key());
  53. }
  54. // Generates a guid, removes the - and then converts it to base64
  55. public static string GenerateShortGuid()
  56. {
  57. Guid guid = Guid.NewGuid();
  58. byte[] bytes = guid.ToByteArray();
  59. string shortGuid = Convert.ToBase64String(bytes);
  60. // Remove padding characters from the end of the Base64 string
  61. shortGuid = shortGuid.TrimEnd('=');
  62. return shortGuid;
  63. }
  64. public static Guid LengthenShortGuid(string shortGuid)
  65. {
  66. // Add padding characters to the end of the Base64 string, if needed
  67. while (shortGuid.Length % 4 != 0)
  68. {
  69. shortGuid += "=";
  70. }
  71. // Convert the Base64 string back to bytes
  72. byte[] bytes = Convert.FromBase64String(shortGuid);
  73. // Create a new GUID from the bytes
  74. Guid guid = new Guid(bytes);
  75. return guid;
  76. }
  77. public static bool VerifyData(string originalMessage, string signedMessage)
  78. {
  79. bool success = false;
  80. using (var rsa = new RSACryptoServiceProvider())
  81. {
  82. var encoder = new UTF8Encoding();
  83. byte[] bytesToVerify = encoder.GetBytes(originalMessage);
  84. byte[] signedBytes = Convert.FromBase64String(signedMessage);
  85. try
  86. {
  87. rsa.FromXmlString(Constants.PublicKey);
  88. SHA512Managed Hash = new SHA512Managed();
  89. byte[] hashedData = Hash.ComputeHash(signedBytes);
  90. success = rsa.VerifyData(bytesToVerify, CryptoConfig.MapNameToOID("SHA512"), signedBytes);
  91. }
  92. catch (CryptographicException e)
  93. {
  94. Console.WriteLine(e.Message);
  95. }
  96. finally
  97. {
  98. rsa.PersistKeyInCsp = false;
  99. }
  100. }
  101. return success;
  102. }
  103. public static string ComputeSignature(string stringToSign, string secret)
  104. {
  105. using (var hmacsha256 = new HMACSHA256(System.Text.ASCIIEncoding.UTF8.GetBytes(secret)))
  106. {
  107. var bytes = Encoding.ASCII.GetBytes(stringToSign);
  108. var hashedBytes = hmacsha256.ComputeHash(bytes);
  109. return Convert.ToBase64String(hashedBytes);
  110. }
  111. }
  112. public static async Task<dynamic> GetSession(string sessionId)
  113. {
  114. string toSign = string.Format($"?s={sessionId}");
  115. string sig = Helpers.ComputeSignature(toSign, Constants.CDPWriteKey);
  116. string URL = string.Format($"https://circleauth.gocircle.ai/api/session/{toSign}&signature={sig}");
  117. try
  118. {
  119. HttpClient client = new HttpClient();
  120. client.Timeout = new TimeSpan(0, 1, 0, 0);
  121. client.DefaultRequestHeaders.Add("x-ua-appKey", Constants.CDPAppKey);
  122. var response = await client.GetAsync(URL);
  123. if (response.StatusCode == System.Net.HttpStatusCode.OK)
  124. {
  125. string responseString = await response.Content.ReadAsStringAsync();
  126. dynamic obj = JObject.Parse(responseString);
  127. dynamic data = obj.data;
  128. return data;
  129. }
  130. }
  131. catch (Exception e)
  132. {
  133. Console.WriteLine(e.Message);
  134. }
  135. return null;
  136. }
  137. public static async Task<Boolean> ExpireSession(string sessionId, string userId)
  138. {
  139. try
  140. {
  141. var dataObj = new { sessionID = sessionId, userID = userId };
  142. var sig = Helpers.ComputeSignature(JsonConvert.SerializeObject(dataObj), Constants.CDPWriteKey);
  143. var obj = new { data = dataObj, signature = sig };
  144. HttpClient client = new HttpClient();
  145. client.Timeout = new TimeSpan(0, 1, 0, 0);
  146. client.DefaultRequestHeaders.Add("x-ua-appKey", Constants.CDPAppKey);
  147. var content = new StringContent(JsonConvert.SerializeObject(obj), Encoding.UTF8, "application/json");
  148. var r = client.PostAsync("https://circleaccess.circlesecurity.ai/api/user/session/expire", content).Result;
  149. return r.StatusCode == HttpStatusCode.OK;
  150. }
  151. catch (Exception e)
  152. {
  153. Console.WriteLine(e);
  154. }
  155. return false;
  156. }
  157. /// <summary>
  158. /// this is the HASH that Circle Auth likes, it's just a SHA265 in hex.
  159. /// </summary>
  160. public static string HashText(string rawData)
  161. {
  162. try
  163. {
  164. // Create a SHA256
  165. using SHA256 sha256Hash = SHA256.Create();
  166. byte[] bytes = sha256Hash.ComputeHash(Encoding.UTF8.GetBytes(rawData));
  167. StringBuilder builder = new();
  168. for (int i = 0; i < bytes.Length; i++)
  169. {
  170. builder.Append(bytes[i].ToString("x2"));
  171. }
  172. return builder.ToString();
  173. }
  174. catch (Exception ex)
  175. {
  176. return null;
  177. }
  178. }
  179. public static string HashAndShortenText(string text)
  180. {
  181. // Hash the email address using SHA-256
  182. using (SHA256 sha256 = SHA256.Create())
  183. {
  184. byte[] hashBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(text));
  185. string shortHash = Convert.ToBase64String(hashBytes);
  186. // make the short hash URL friendly
  187. shortHash = shortHash.Replace("+", "-").Replace("/", "_");
  188. // Remove padding characters from the end of the Base64 string
  189. shortHash = shortHash.TrimEnd('=');
  190. return shortHash;
  191. }
  192. }
  193. public static async Task<SingleLogin> CreateSession(string customerAppKey, string returnURL, string payloadJson, string webHook = "")
  194. {
  195. var client = new HttpClient();
  196. // wacky hack since I can't declare anonymous variables without initializing them
  197. var payloadObject = new
  198. {
  199. Test = "123"
  200. };
  201. var dataObj = new
  202. {
  203. payload = payloadJson,
  204. customerAppKey = customerAppKey,
  205. customID = "blahORama",
  206. returnUrl = returnURL,
  207. mobileUrl = returnURL,
  208. webhookUrl = webHook
  209. };
  210. var sig = Helpers.ComputeSignature(JsonConvert.SerializeObject(dataObj), Constants.CDPWriteKey);
  211. var obj = new { data = dataObj, signature = sig };
  212. string json = JsonConvert.SerializeObject(obj);
  213. client.DefaultRequestHeaders.Add("x-ua-appKey", Constants.CDPAppKey);
  214. HttpContent c = new StringContent(json, Encoding.UTF8, "application/json");
  215. var response = await client.PostAsync(new Uri("https://circleaccess.circlesecurity.ai/api/single/create"), c);
  216. SingleLogin sl = new SingleLogin();
  217. if (response.StatusCode == System.Net.HttpStatusCode.OK)
  218. {
  219. string body = response.Content.ReadAsStringAsync().Result; //right!
  220. dynamic stuff = JObject.Parse(body);
  221. sl.QRCodeUrl = stuff.data.qrcode.ToString();
  222. sl.LoginId = stuff.data.singleLoginID.ToString();
  223. return sl;
  224. }
  225. return null;
  226. }
  227. }
  228. public class KeyVaultService
  229. {
  230. private readonly string _keyVaultUrl;
  231. public KeyVaultService(string keyVaultUrl)
  232. {
  233. _keyVaultUrl = keyVaultUrl;
  234. }
  235. public async Task SetSecretAsync(string secretName, string secretValue)
  236. {
  237. #if DEBUG
  238. var client = new SecretClient(new Uri(_keyVaultUrl), new VisualStudioCredential());
  239. #else
  240. var client = new SecretClient(new Uri(_keyVaultUrl), new DefaultAzureCredential());
  241. #endif
  242. // Set the secret in the Key Vault
  243. await client.SetSecretAsync(secretName, secretValue);
  244. }
  245. public async Task<string> GetSecretAsync(string secretName)
  246. {
  247. #if DEBUG
  248. var client = new SecretClient(new Uri(_keyVaultUrl), new VisualStudioCredential());
  249. #else
  250. var client = new SecretClient(new Uri(_keyVaultUrl), new DefaultAzureCredential());
  251. #endif
  252. // Set the secret in the Key Vault
  253. KeyVaultSecret kvs = await client.GetSecretAsync(secretName);
  254. return kvs.Value;
  255. }
  256. }
  257. public class SingleLogin
  258. {
  259. public string QRCodeUrl { get; set; }
  260. public string LoginId { get; set; }
  261. public SingleLogin()
  262. {
  263. }
  264. public override string ToString()
  265. {
  266. return QRCodeUrl;
  267. }
  268. }
  269. }