LicenseUtils.cs 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Diagnostics;
  4. using System.Diagnostics.CodeAnalysis;
  5. using System.IO;
  6. using System.Linq;
  7. namespace InABox.Core
  8. {
  9. public static class LicenseUtils
  10. {
  11. #region License Generation
  12. /// <summary>
  13. /// Generate a new, out-of-the-box license.
  14. /// </summary>
  15. /// <returns>The new license, valid for 1 month.</returns>
  16. public static LicenseData GenerateNewLicense()
  17. {
  18. return new LicenseData
  19. {
  20. LastRenewal = DateTime.Now,
  21. Expiry = DateTime.Now.AddMonths(1),
  22. CustomerID = Guid.Empty,
  23. RenewalAvailable = DateTime.Now.AddMonths(1).AddDays(-7)
  24. };
  25. }
  26. public static LicenseData RenewLicense(LicenseData oldLicense, DateTime renewed, DateTime newExpiry, DateTime renewAvailable)
  27. {
  28. return new LicenseData
  29. {
  30. LastRenewal = renewed,
  31. Expiry = newExpiry,
  32. CustomerID = oldLicense.CustomerID,
  33. RenewalAvailable = renewAvailable
  34. };
  35. }
  36. private static readonly byte[] LicenseKey = Convert.FromBase64String("dCyTyQkj1o1rqJJQlT+Jcnkxr+OQnO4KCoF/b+6cx54=");
  37. /// <summary>
  38. /// Encrypts the license data.
  39. /// </summary>
  40. /// <param name="license">The license to encrypt.</param>
  41. /// <returns>
  42. /// The encrypted data.
  43. /// </returns>
  44. public static string? EncryptLicense(LicenseData license)
  45. {
  46. return Encryption.EncryptV2(Serialization.Serialize(license), LicenseKey);
  47. }
  48. public static bool TryEncryptLicense(LicenseData license, [NotNullWhen(true)] out string? result, [NotNullWhen(false)] out string? error)
  49. {
  50. return Encryption.TryEncryptV2(Serialization.Serialize(license), LicenseKey, out result, out error);
  51. }
  52. /// <summary>
  53. /// Decrypts <paramref name="license"/>.
  54. /// </summary>
  55. /// <param name="license">The license to decrypt.</param>
  56. /// <returns>
  57. /// The new license data, or <see langword="null"/> if errors occurred.
  58. /// </returns>
  59. public static bool TryDecryptLicense(string data, [NotNullWhen(true)] out LicenseData? result, [NotNullWhen(false)] out string? error)
  60. {
  61. if (!Encryption.TryDecryptV2(data, LicenseKey, out var decrypted, out error))
  62. {
  63. result = null;
  64. return false;
  65. }
  66. result = Serialization.Deserialize<LicenseData>(decrypted);
  67. if(result == null)
  68. {
  69. error = "License deserialization failed";
  70. return false;
  71. }
  72. return true;
  73. }
  74. /// <summary>
  75. /// Decrypts <paramref name="license"/>, throwing an <see cref="Exception"/> on fail.
  76. /// </summary>
  77. /// <param name="license">The license to decrypt.</param>
  78. /// <returns>
  79. /// The new license data.
  80. /// </returns>
  81. public static LicenseData DecryptLicense(string data)
  82. {
  83. if (!TryDecryptLicense(data, out var result, out var error))
  84. throw new Exception(error);
  85. return result;
  86. }
  87. #endregion
  88. #region Fees & Discounts
  89. private static readonly Dictionary<Type, double> _licensefees = new Dictionary<Type, double>();
  90. private static readonly Dictionary<int, double> _periods = new Dictionary<int, double>();
  91. private static readonly Dictionary<int, double> _userDiscounts = new Dictionary<int, double>();
  92. public static double GetLicenseFee(Type type)
  93. {
  94. return _licensefees.GetValueOrDefault(type, 0);
  95. }
  96. public static double GetLicenseFee<T>() where T : LicenseToken
  97. {
  98. return GetLicenseFee(typeof(T));
  99. }
  100. public static IEnumerable<Type> LicenseTypes()
  101. {
  102. return _licensefees.Keys;
  103. }
  104. public static double GetUserDiscount(int users)
  105. {
  106. var key = _userDiscounts.Keys
  107. .Where(x => x <= users)
  108. .DefaultIfEmpty(-1)
  109. .Max();
  110. if (key == -1)
  111. return 0;
  112. return _userDiscounts[key];
  113. }
  114. public static double GetTimeDiscount(int months)
  115. {
  116. var period = _periods.Keys
  117. .Where(x => x <= months)
  118. .DefaultIfEmpty(-1)
  119. .Max();
  120. if (period == -1)
  121. return 0;
  122. return _periods[period];
  123. }
  124. public static IEnumerable<int> TimeDiscountLevels()
  125. {
  126. return _periods.Keys;
  127. }
  128. public static double CalculateLicenseFee(Dictionary<Type, int> licenses, int time)
  129. {
  130. double licensefee = 0.00F;
  131. foreach (var license in licenses.Keys)
  132. if (_licensefees.ContainsKey(license))
  133. licensefee += _licensefees[license] * licenses[license];
  134. var users = licenses.Values.OrderBy(x => x).LastOrDefault();
  135. var userdiscount = GetUserDiscount(users);
  136. var timediscount = GetTimeDiscount(time);
  137. var result = licensefee * ((100.0F - userdiscount) / 100.0F) * ((100.0F - timediscount) / 100.0F);
  138. return result;
  139. }
  140. public static void LoadSummary(LicenseSummary summary)
  141. {
  142. _licensefees.Clear();
  143. _periods.Clear();
  144. _userDiscounts.Clear();
  145. foreach (var license in summary.LicenseFees)
  146. _licensefees[CoreUtils.GetEntity(license.Key)] = license.Value;
  147. foreach (var (months, period) in summary.TimeDiscounts)
  148. _periods[months] = period;
  149. foreach (var (users, discount) in summary.UserDiscounts)
  150. _userDiscounts[users] = discount;
  151. }
  152. /// <summary>
  153. /// Gets a map from entities to their associated licenses.
  154. /// </summary>
  155. /// <returns>A map of entity types to license types.</returns>
  156. public static Dictionary<Type, Type> LicenseMap()
  157. {
  158. var result = new Dictionary<Type, Type>();
  159. var licenses = CoreUtils.TypeList(
  160. AppDomain.CurrentDomain.GetAssemblies(),
  161. myType =>
  162. myType.IsClass
  163. && !myType.IsAbstract
  164. && !myType.IsGenericType
  165. && myType.IsSubclassOf(typeof(LicenseToken))
  166. ).ToArray();
  167. var entities = CoreUtils.TypeList(
  168. AppDomain.CurrentDomain.GetAssemblies(),
  169. myType =>
  170. myType.IsClass
  171. && !myType.IsAbstract
  172. && !myType.IsGenericType
  173. && myType.IsSubclassOf(typeof(Entity))
  174. ).ToArray();
  175. foreach (var entity in entities)
  176. {
  177. var lic = entity.GetInterfaces()
  178. .FirstOrDefault(x => x.IsConstructedGenericType && x.GetGenericTypeDefinition() == typeof(ILicense<>));
  179. result[entity] = lic?.GenericTypeArguments.FirstOrDefault();
  180. }
  181. return result;
  182. }
  183. public static void SaveLicenseSummary(string filename)
  184. {
  185. var entitymap = LicenseMap();
  186. var summary = new List<string> { "\"License Token\",\"Class Name\"" };
  187. foreach (var mapentry in entitymap.OrderBy(x => x.Value))
  188. summary.Add(string.Format("\"{0}\",\"{1}\"", mapentry.Value?.GetCaption(), mapentry.Value.EntityName()));
  189. File.WriteAllLines(filename, summary.ToArray());
  190. }
  191. public static void Reset()
  192. {
  193. _licensefees.Clear();
  194. _periods.Clear();
  195. _userDiscounts.Clear();
  196. }
  197. #endregion
  198. }
  199. public class LicenseSummary
  200. {
  201. public LicenseSummary()
  202. {
  203. LicenseFees = new Dictionary<string, double>();
  204. TimeDiscounts = new Dictionary<int, double>();
  205. UserDiscounts = new Dictionary<int, double>();
  206. }
  207. public Dictionary<string, double> LicenseFees { get; set; }
  208. public Dictionary<int, double> TimeDiscounts { get; set; }
  209. public Dictionary<int, double> UserDiscounts { get; set; }
  210. }
  211. }