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.

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