User.cs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521
  1. using System;
  2. using System.Collections.Generic;
  3. using System.ComponentModel;
  4. using System.ComponentModel.DataAnnotations;
  5. using System.ComponentModel.DataAnnotations.Schema;
  6. using System.Linq;
  7. using System.Text.Json.Serialization;
  8. using Jellyfin.Data.Enums;
  9. using Jellyfin.Data.Interfaces;
  10. namespace Jellyfin.Data.Entities
  11. {
  12. /// <summary>
  13. /// An entity representing a user.
  14. /// </summary>
  15. public class User : IHasPermissions, IHasConcurrencyToken
  16. {
  17. /// <summary>
  18. /// The values being delimited here are Guids, so commas work as they do not appear in Guids.
  19. /// </summary>
  20. private const char Delimiter = ',';
  21. /// <summary>
  22. /// Initializes a new instance of the <see cref="User"/> class.
  23. /// Public constructor with required data.
  24. /// </summary>
  25. /// <param name="username">The username for the new user.</param>
  26. /// <param name="authenticationProviderId">The Id of the user's authentication provider.</param>
  27. /// <param name="passwordResetProviderId">The Id of the user's password reset provider.</param>
  28. public User(string username, string authenticationProviderId, string passwordResetProviderId)
  29. {
  30. if (string.IsNullOrEmpty(username))
  31. {
  32. throw new ArgumentNullException(nameof(username));
  33. }
  34. if (string.IsNullOrEmpty(authenticationProviderId))
  35. {
  36. throw new ArgumentNullException(nameof(authenticationProviderId));
  37. }
  38. if (string.IsNullOrEmpty(passwordResetProviderId))
  39. {
  40. throw new ArgumentNullException(nameof(passwordResetProviderId));
  41. }
  42. Username = username;
  43. AuthenticationProviderId = authenticationProviderId;
  44. PasswordResetProviderId = passwordResetProviderId;
  45. AccessSchedules = new HashSet<AccessSchedule>();
  46. DisplayPreferences = new HashSet<DisplayPreferences>();
  47. ItemDisplayPreferences = new HashSet<ItemDisplayPreferences>();
  48. // Groups = new HashSet<Group>();
  49. Permissions = new HashSet<Permission>();
  50. Preferences = new HashSet<Preference>();
  51. // ProviderMappings = new HashSet<ProviderMapping>();
  52. // Set default values
  53. Id = Guid.NewGuid();
  54. InvalidLoginAttemptCount = 0;
  55. EnableUserPreferenceAccess = true;
  56. MustUpdatePassword = false;
  57. DisplayMissingEpisodes = false;
  58. DisplayCollectionsView = false;
  59. HidePlayedInLatest = true;
  60. RememberAudioSelections = true;
  61. RememberSubtitleSelections = true;
  62. EnableNextEpisodeAutoPlay = true;
  63. EnableAutoLogin = false;
  64. PlayDefaultAudioTrack = true;
  65. SubtitleMode = SubtitlePlaybackMode.Default;
  66. SyncPlayAccess = SyncPlayUserAccessType.CreateAndJoinGroups;
  67. }
  68. /// <summary>
  69. /// Gets or sets the Id of the user.
  70. /// </summary>
  71. /// <remarks>
  72. /// Identity, Indexed, Required.
  73. /// </remarks>
  74. [JsonIgnore]
  75. public Guid Id { get; set; }
  76. /// <summary>
  77. /// Gets or sets the user's name.
  78. /// </summary>
  79. /// <remarks>
  80. /// Required, Max length = 255.
  81. /// </remarks>
  82. [MaxLength(255)]
  83. [StringLength(255)]
  84. public string Username { get; set; }
  85. /// <summary>
  86. /// Gets or sets the user's password, or <c>null</c> if none is set.
  87. /// </summary>
  88. /// <remarks>
  89. /// Max length = 65535.
  90. /// </remarks>
  91. [MaxLength(65535)]
  92. [StringLength(65535)]
  93. public string? Password { get; set; }
  94. /// <summary>
  95. /// Gets or sets the user's easy password, or <c>null</c> if none is set.
  96. /// </summary>
  97. /// <remarks>
  98. /// Max length = 65535.
  99. /// </remarks>
  100. [MaxLength(65535)]
  101. [StringLength(65535)]
  102. public string? EasyPassword { get; set; }
  103. /// <summary>
  104. /// Gets or sets a value indicating whether the user must update their password.
  105. /// </summary>
  106. /// <remarks>
  107. /// Required.
  108. /// </remarks>
  109. public bool MustUpdatePassword { get; set; }
  110. /// <summary>
  111. /// Gets or sets the audio language preference.
  112. /// </summary>
  113. /// <remarks>
  114. /// Max length = 255.
  115. /// </remarks>
  116. [MaxLength(255)]
  117. [StringLength(255)]
  118. public string? AudioLanguagePreference { get; set; }
  119. /// <summary>
  120. /// Gets or sets the authentication provider id.
  121. /// </summary>
  122. /// <remarks>
  123. /// Required, Max length = 255.
  124. /// </remarks>
  125. [MaxLength(255)]
  126. [StringLength(255)]
  127. public string AuthenticationProviderId { get; set; }
  128. /// <summary>
  129. /// Gets or sets the password reset provider id.
  130. /// </summary>
  131. /// <remarks>
  132. /// Required, Max length = 255.
  133. /// </remarks>
  134. [MaxLength(255)]
  135. [StringLength(255)]
  136. public string PasswordResetProviderId { get; set; }
  137. /// <summary>
  138. /// Gets or sets the invalid login attempt count.
  139. /// </summary>
  140. /// <remarks>
  141. /// Required.
  142. /// </remarks>
  143. public int InvalidLoginAttemptCount { get; set; }
  144. /// <summary>
  145. /// Gets or sets the last activity date.
  146. /// </summary>
  147. public DateTime? LastActivityDate { get; set; }
  148. /// <summary>
  149. /// Gets or sets the last login date.
  150. /// </summary>
  151. public DateTime? LastLoginDate { get; set; }
  152. /// <summary>
  153. /// Gets or sets the number of login attempts the user can make before they are locked out.
  154. /// </summary>
  155. public int? LoginAttemptsBeforeLockout { get; set; }
  156. /// <summary>
  157. /// Gets or sets the maximum number of active sessions the user can have at once.
  158. /// </summary>
  159. public int MaxActiveSessions { get; set; }
  160. /// <summary>
  161. /// Gets or sets the subtitle mode.
  162. /// </summary>
  163. /// <remarks>
  164. /// Required.
  165. /// </remarks>
  166. public SubtitlePlaybackMode SubtitleMode { get; set; }
  167. /// <summary>
  168. /// Gets or sets a value indicating whether the default audio track should be played.
  169. /// </summary>
  170. /// <remarks>
  171. /// Required.
  172. /// </remarks>
  173. public bool PlayDefaultAudioTrack { get; set; }
  174. /// <summary>
  175. /// Gets or sets the subtitle language preference.
  176. /// </summary>
  177. /// <remarks>
  178. /// Max length = 255.
  179. /// </remarks>
  180. [MaxLength(255)]
  181. [StringLength(255)]
  182. public string? SubtitleLanguagePreference { get; set; }
  183. /// <summary>
  184. /// Gets or sets a value indicating whether missing episodes should be displayed.
  185. /// </summary>
  186. /// <remarks>
  187. /// Required.
  188. /// </remarks>
  189. public bool DisplayMissingEpisodes { get; set; }
  190. /// <summary>
  191. /// Gets or sets a value indicating whether to display the collections view.
  192. /// </summary>
  193. /// <remarks>
  194. /// Required.
  195. /// </remarks>
  196. public bool DisplayCollectionsView { get; set; }
  197. /// <summary>
  198. /// Gets or sets a value indicating whether the user has a local password.
  199. /// </summary>
  200. /// <remarks>
  201. /// Required.
  202. /// </remarks>
  203. public bool EnableLocalPassword { get; set; }
  204. /// <summary>
  205. /// Gets or sets a value indicating whether the server should hide played content in "Latest".
  206. /// </summary>
  207. /// <remarks>
  208. /// Required.
  209. /// </remarks>
  210. public bool HidePlayedInLatest { get; set; }
  211. /// <summary>
  212. /// Gets or sets a value indicating whether to remember audio selections on played content.
  213. /// </summary>
  214. /// <remarks>
  215. /// Required.
  216. /// </remarks>
  217. public bool RememberAudioSelections { get; set; }
  218. /// <summary>
  219. /// Gets or sets a value indicating whether to remember subtitle selections on played content.
  220. /// </summary>
  221. /// <remarks>
  222. /// Required.
  223. /// </remarks>
  224. public bool RememberSubtitleSelections { get; set; }
  225. /// <summary>
  226. /// Gets or sets a value indicating whether to enable auto-play for the next episode.
  227. /// </summary>
  228. /// <remarks>
  229. /// Required.
  230. /// </remarks>
  231. public bool EnableNextEpisodeAutoPlay { get; set; }
  232. /// <summary>
  233. /// Gets or sets a value indicating whether the user should auto-login.
  234. /// </summary>
  235. /// <remarks>
  236. /// Required.
  237. /// </remarks>
  238. public bool EnableAutoLogin { get; set; }
  239. /// <summary>
  240. /// Gets or sets a value indicating whether the user can change their preferences.
  241. /// </summary>
  242. /// <remarks>
  243. /// Required.
  244. /// </remarks>
  245. public bool EnableUserPreferenceAccess { get; set; }
  246. /// <summary>
  247. /// Gets or sets the maximum parental age rating.
  248. /// </summary>
  249. public int? MaxParentalAgeRating { get; set; }
  250. /// <summary>
  251. /// Gets or sets the remote client bitrate limit.
  252. /// </summary>
  253. public int? RemoteClientBitrateLimit { get; set; }
  254. /// <summary>
  255. /// Gets or sets the internal id.
  256. /// This is a temporary stopgap for until the library db is migrated.
  257. /// This corresponds to the value of the index of this user in the library db.
  258. /// </summary>
  259. public long InternalId { get; set; }
  260. /// <summary>
  261. /// Gets or sets the user's profile image. Can be <c>null</c>.
  262. /// </summary>
  263. // [ForeignKey("UserId")]
  264. public virtual ImageInfo? ProfileImage { get; set; }
  265. /// <summary>
  266. /// Gets the user's display preferences.
  267. /// </summary>
  268. public virtual ICollection<DisplayPreferences> DisplayPreferences { get; private set; }
  269. /// <summary>
  270. /// Gets or sets the level of sync play permissions this user has.
  271. /// </summary>
  272. public SyncPlayUserAccessType SyncPlayAccess { get; set; }
  273. /// <inheritdoc />
  274. [ConcurrencyCheck]
  275. public uint RowVersion { get; private set; }
  276. /// <summary>
  277. /// Gets the list of access schedules this user has.
  278. /// </summary>
  279. public virtual ICollection<AccessSchedule> AccessSchedules { get; private set; }
  280. /// <summary>
  281. /// Gets the list of item display preferences.
  282. /// </summary>
  283. public virtual ICollection<ItemDisplayPreferences> ItemDisplayPreferences { get; private set; }
  284. /*
  285. /// <summary>
  286. /// Gets the list of groups this user is a member of.
  287. /// </summary>
  288. public virtual ICollection<Group> Groups { get; private set; }
  289. */
  290. /// <summary>
  291. /// Gets the list of permissions this user has.
  292. /// </summary>
  293. [ForeignKey("Permission_Permissions_Guid")]
  294. public virtual ICollection<Permission> Permissions { get; private set; }
  295. /*
  296. /// <summary>
  297. /// Gets the list of provider mappings this user has.
  298. /// </summary>
  299. public virtual ICollection<ProviderMapping> ProviderMappings { get; private set; }
  300. */
  301. /// <summary>
  302. /// Gets the list of preferences this user has.
  303. /// </summary>
  304. [ForeignKey("Preference_Preferences_Guid")]
  305. public virtual ICollection<Preference> Preferences { get; private set; }
  306. /// <inheritdoc/>
  307. public void OnSavingChanges()
  308. {
  309. RowVersion++;
  310. }
  311. /// <summary>
  312. /// Checks whether the user has the specified permission.
  313. /// </summary>
  314. /// <param name="kind">The permission kind.</param>
  315. /// <returns><c>True</c> if the user has the specified permission.</returns>
  316. public bool HasPermission(PermissionKind kind)
  317. {
  318. return Permissions.First(p => p.Kind == kind).Value;
  319. }
  320. /// <summary>
  321. /// Sets the given permission kind to the provided value.
  322. /// </summary>
  323. /// <param name="kind">The permission kind.</param>
  324. /// <param name="value">The value to set.</param>
  325. public void SetPermission(PermissionKind kind, bool value)
  326. {
  327. Permissions.First(p => p.Kind == kind).Value = value;
  328. }
  329. /// <summary>
  330. /// Gets the user's preferences for the given preference kind.
  331. /// </summary>
  332. /// <param name="preference">The preference kind.</param>
  333. /// <returns>A string array containing the user's preferences.</returns>
  334. public string[] GetPreference(PreferenceKind preference)
  335. {
  336. var val = Preferences.First(p => p.Kind == preference).Value;
  337. return Equals(val, string.Empty) ? Array.Empty<string>() : val.Split(Delimiter);
  338. }
  339. /// <summary>
  340. /// Gets the user's preferences for the given preference kind.
  341. /// </summary>
  342. /// <param name="preference">The preference kind.</param>
  343. /// <typeparam name="T">Type of preference.</typeparam>
  344. /// <returns>A {T} array containing the user's preference.</returns>
  345. public T[] GetPreferenceValues<T>(PreferenceKind preference)
  346. {
  347. var val = Preferences.First(p => p.Kind == preference).Value;
  348. if (string.IsNullOrEmpty(val))
  349. {
  350. return Array.Empty<T>();
  351. }
  352. // Convert array of {string} to array of {T}
  353. var converter = TypeDescriptor.GetConverter(typeof(T));
  354. var stringValues = val.Split(Delimiter);
  355. var convertedCount = 0;
  356. var parsedValues = new T[stringValues.Length];
  357. for (var i = 0; i < stringValues.Length; i++)
  358. {
  359. try
  360. {
  361. var parsedValue = converter.ConvertFromString(stringValues[i].Trim());
  362. if (parsedValue != null)
  363. {
  364. parsedValues[convertedCount++] = (T)parsedValue;
  365. }
  366. }
  367. catch (FormatException)
  368. {
  369. // Unable to convert value
  370. }
  371. }
  372. return parsedValues[..convertedCount];
  373. }
  374. /// <summary>
  375. /// Sets the specified preference to the given value.
  376. /// </summary>
  377. /// <param name="preference">The preference kind.</param>
  378. /// <param name="values">The values.</param>
  379. public void SetPreference(PreferenceKind preference, string[] values)
  380. {
  381. Preferences.First(p => p.Kind == preference).Value
  382. = string.Join(Delimiter, values);
  383. }
  384. /// <summary>
  385. /// Sets the specified preference to the given value.
  386. /// </summary>
  387. /// <param name="preference">The preference kind.</param>
  388. /// <param name="values">The values.</param>
  389. /// <typeparam name="T">The type of value.</typeparam>
  390. public void SetPreference<T>(PreferenceKind preference, T[] values)
  391. {
  392. Preferences.First(p => p.Kind == preference).Value
  393. = string.Join(Delimiter, values);
  394. }
  395. /// <summary>
  396. /// Checks whether this user is currently allowed to use the server.
  397. /// </summary>
  398. /// <returns><c>True</c> if the current time is within an access schedule, or there are no access schedules.</returns>
  399. public bool IsParentalScheduleAllowed()
  400. {
  401. return AccessSchedules.Count == 0
  402. || AccessSchedules.Any(i => IsParentalScheduleAllowed(i, DateTime.UtcNow));
  403. }
  404. /// <summary>
  405. /// Checks whether the provided folder is in this user's grouped folders.
  406. /// </summary>
  407. /// <param name="id">The Guid of the folder.</param>
  408. /// <returns><c>True</c> if the folder is in the user's grouped folders.</returns>
  409. public bool IsFolderGrouped(Guid id)
  410. {
  411. return Array.IndexOf(GetPreferenceValues<Guid>(PreferenceKind.GroupedFolders), id) != -1;
  412. }
  413. /// <summary>
  414. /// Initializes the default permissions for a user. Should only be called on user creation.
  415. /// </summary>
  416. // TODO: make these user configurable?
  417. public void AddDefaultPermissions()
  418. {
  419. Permissions.Add(new Permission(PermissionKind.IsAdministrator, false));
  420. Permissions.Add(new Permission(PermissionKind.IsDisabled, false));
  421. Permissions.Add(new Permission(PermissionKind.IsHidden, true));
  422. Permissions.Add(new Permission(PermissionKind.EnableAllChannels, true));
  423. Permissions.Add(new Permission(PermissionKind.EnableAllDevices, true));
  424. Permissions.Add(new Permission(PermissionKind.EnableAllFolders, true));
  425. Permissions.Add(new Permission(PermissionKind.EnableContentDeletion, false));
  426. Permissions.Add(new Permission(PermissionKind.EnableContentDownloading, true));
  427. Permissions.Add(new Permission(PermissionKind.EnableMediaConversion, true));
  428. Permissions.Add(new Permission(PermissionKind.EnableMediaPlayback, true));
  429. Permissions.Add(new Permission(PermissionKind.EnablePlaybackRemuxing, true));
  430. Permissions.Add(new Permission(PermissionKind.EnablePublicSharing, true));
  431. Permissions.Add(new Permission(PermissionKind.EnableRemoteAccess, true));
  432. Permissions.Add(new Permission(PermissionKind.EnableSyncTranscoding, true));
  433. Permissions.Add(new Permission(PermissionKind.EnableAudioPlaybackTranscoding, true));
  434. Permissions.Add(new Permission(PermissionKind.EnableLiveTvAccess, true));
  435. Permissions.Add(new Permission(PermissionKind.EnableLiveTvManagement, true));
  436. Permissions.Add(new Permission(PermissionKind.EnableSharedDeviceControl, true));
  437. Permissions.Add(new Permission(PermissionKind.EnableVideoPlaybackTranscoding, true));
  438. Permissions.Add(new Permission(PermissionKind.ForceRemoteSourceTranscoding, false));
  439. Permissions.Add(new Permission(PermissionKind.EnableRemoteControlOfOtherUsers, false));
  440. }
  441. /// <summary>
  442. /// Initializes the default preferences. Should only be called on user creation.
  443. /// </summary>
  444. public void AddDefaultPreferences()
  445. {
  446. foreach (var val in Enum.GetValues(typeof(PreferenceKind)).Cast<PreferenceKind>())
  447. {
  448. Preferences.Add(new Preference(val, string.Empty));
  449. }
  450. }
  451. private static bool IsParentalScheduleAllowed(AccessSchedule schedule, DateTime date)
  452. {
  453. var localTime = date.ToLocalTime();
  454. var hour = localTime.TimeOfDay.TotalHours;
  455. return DayOfWeekHelper.GetDaysOfWeek(schedule.DayOfWeek).Contains(localTime.DayOfWeek)
  456. && hour >= schedule.StartHour
  457. && hour <= schedule.EndHour;
  458. }
  459. }
  460. }