Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.
 
 
 
 

198 wiersze
7.0 KiB

  1. //
  2. // UniWebViewAuthenticationUtils.cs
  3. // Created by Wang Wei (@onevcat) on 2022-06-25.
  4. //
  5. // This file is a part of UniWebView Project (https://uniwebview.com)
  6. // By purchasing the asset, you are allowed to use this code in as many as projects
  7. // you want, only if you publish the final products under the name of the same account
  8. // used for the purchase.
  9. //
  10. // This asset and all corresponding files (such as source code) are provided on an
  11. // “as is” basis, without warranty of any kind, express of implied, including but not
  12. // limited to the warranties of merchantability, fitness for a particular purpose, and
  13. // noninfringement. In no event shall the authors or copyright holders be liable for any
  14. // claim, damages or other liability, whether in action of contract, tort or otherwise,
  15. // arising from, out of or in connection with the software or the use of other dealing in the software.
  16. //
  17. using System;
  18. using System.Collections.Generic;
  19. using System.Linq;
  20. using System.Security.Cryptography;
  21. using System.Text;
  22. using UnityEngine.Networking;
  23. /// <summary>
  24. /// This class provides some helper utils for performing the authentication flow.
  25. ///
  26. /// They are used inside the built-in flows, but you can also use them to implement your own flow.
  27. /// </summary>
  28. public class UniWebViewAuthenticationUtils {
  29. internal static Dictionary<string, string> ParseFormUrlEncodedString(string input) {
  30. var result = new Dictionary<string, string>();
  31. if (input.StartsWith("?") || input.StartsWith("#")) {
  32. input = input.Substring(1);
  33. }
  34. var pairs = input.Split('&');
  35. foreach (var pair in pairs) {
  36. var kv = pair.Split('=');
  37. result.Add(UnityWebRequest.UnEscapeURL(kv[0]), UnityWebRequest.UnEscapeURL(kv[1]));
  38. }
  39. return result;
  40. }
  41. /// <summary>
  42. /// Generates a random Base64 encoded string.
  43. /// </summary>
  44. /// <returns>A random Base64 encoded string.</returns>
  45. public static string GenerateRandomBase64String() {
  46. var randomNumber = new byte[32];
  47. string value = "";
  48. using (var rng = RandomNumberGenerator.Create()) {
  49. rng.GetBytes(randomNumber);
  50. value = Convert.ToBase64String(randomNumber);
  51. }
  52. return value;
  53. }
  54. /// <summary>
  55. /// Generates a random Base64URL encoded string.
  56. /// </summary>
  57. /// <returns>A random Base64URL encoded string.</returns>
  58. public static string GenerateRandomBase64URLString() {
  59. var value = GenerateRandomBase64String();
  60. return ConvertToBase64URLString(value);
  61. }
  62. static readonly char[] padding = { '=' };
  63. /// <summary>
  64. /// Converts a Base64 encoded string to a Base64URL encoded string.
  65. /// </summary>
  66. /// <param name="input">The Base64 encoded string.</param>
  67. /// <returns>A string with Base64URL encoded for the input.</returns>
  68. public static string ConvertToBase64URLString(string input) {
  69. return input.TrimEnd(padding).Replace('+', '-').Replace('/', '_');
  70. }
  71. /// <summary>
  72. /// Converts a Base64URL encoded string to a Base64 encoded string.
  73. /// </summary>
  74. /// <param name="input">The Base64URL encoded string.</param>
  75. /// <returns>A string with Base64 encoded for the input.</returns>
  76. public static string ConvertToBase64String(string input) {
  77. var result = input.Replace('_', '/').Replace('-', '+');
  78. switch (input.Length % 4) {
  79. case 2:
  80. result += "==";
  81. break;
  82. case 3:
  83. result += "=";
  84. break;
  85. }
  86. return result;
  87. }
  88. /// <summary>
  89. /// Generates a code verifier for PKCE usage.
  90. /// </summary>
  91. /// <param name="length">The length of the target code verifier. Default is 64.</param>
  92. /// <returns>A generated code verifier for PKCE usage.</returns>
  93. public static string GenerateCodeVerifier(int length = 64) {
  94. var randomNumber = new byte[32];
  95. string value;
  96. using var rng = RandomNumberGenerator.Create();
  97. rng.GetBytes(randomNumber);
  98. const string chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.~";
  99. var random = new Random(System.BitConverter.ToInt32(randomNumber, 0));
  100. value = new string(Enumerable.Repeat(chars, length).Select(s => s[random.Next(s.Length)]).ToArray());
  101. return value;
  102. }
  103. /// <summary>
  104. /// Calculates the code challenge for PKCE usage, with a given code verifier and hash method.
  105. /// </summary>
  106. /// <param name="codeVerifier">The code verifier you generated.</param>
  107. /// <param name="method">The hash method you want to use.</param>
  108. /// <returns>The result of the code challenge.</returns>
  109. public static string CalculateCodeChallenge(string codeVerifier, UniWebViewAuthenticationPKCE method) {
  110. switch (method) {
  111. case UniWebViewAuthenticationPKCE.None:
  112. throw new ArgumentOutOfRangeException(nameof(method), method, null);
  113. case UniWebViewAuthenticationPKCE.S256:
  114. var sha256 = SHA256.Create();
  115. var hash = sha256.ComputeHash(System.Text.Encoding.UTF8.GetBytes(codeVerifier));
  116. return ConvertToBase64URLString(System.Convert.ToBase64String(hash));
  117. case UniWebViewAuthenticationPKCE.Plain:
  118. return codeVerifier;
  119. default:
  120. throw new ArgumentOutOfRangeException(nameof(method), method, null);
  121. }
  122. }
  123. public static string ConvertPKCEToString(UniWebViewAuthenticationPKCE method) {
  124. switch (method) {
  125. case UniWebViewAuthenticationPKCE.None:
  126. return null;
  127. case UniWebViewAuthenticationPKCE.S256:
  128. return "S256";
  129. case UniWebViewAuthenticationPKCE.Plain:
  130. return "plain";
  131. }
  132. return null;
  133. }
  134. public static string ConvertIntentUri(string input) {
  135. var uri = new Uri(input);
  136. if (uri.Scheme != "intent") {
  137. return input;
  138. }
  139. var host = uri.Host;
  140. string scheme = null;
  141. var fragments = uri.Fragment;
  142. fragments.Split(';').ToList().ForEach(fragment => {
  143. var kv = fragment.Split('=');
  144. if (kv.Length == 2 && kv[0] == "scheme") {
  145. scheme = kv[1];
  146. }
  147. });
  148. if (!String.IsNullOrEmpty(scheme)) {
  149. return scheme + "://" + host;
  150. }
  151. return input;
  152. }
  153. public static string CreateQueryString(Dictionary<string, string> collection) {
  154. int count = collection.Count;
  155. if (count == 0) {
  156. return "";
  157. }
  158. StringBuilder sb = new StringBuilder();
  159. string [] keys = collection.Keys.ToArray();
  160. for (int i = 0; i < count; i++) {
  161. sb.AppendFormat ("{0}={1}&", keys[i], UnityWebRequest.EscapeURL(collection[keys[i]]));
  162. }
  163. if (sb.Length > 0) {
  164. sb.Length--;
  165. }
  166. return sb.ToString();
  167. }
  168. }
  169. public enum UniWebViewAuthenticationPKCE
  170. {
  171. None,
  172. S256,
  173. Plain
  174. }