diff options
14 files changed, 840 insertions, 116 deletions
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 9a929a8b0..9ee292f79 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -22,7 +22,7 @@ jobs: - name: Checkout repository uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 - name: Setup .NET - uses: actions/setup-dotnet@aa983c550dfda0d1722b6ac6aed55724ffacc6d3 # v3.1.0 + uses: actions/setup-dotnet@3447fd6a9f9e57506b15f895c5b76d3b197dc7c2 # v3.2.0 with: dotnet-version: '7.0.x' diff --git a/.github/workflows/openapi.yml b/.github/workflows/openapi.yml index c2387f2ef..539da7aef 100644 --- a/.github/workflows/openapi.yml +++ b/.github/workflows/openapi.yml @@ -19,7 +19,7 @@ jobs: ref: ${{ github.event.pull_request.head.sha }} repository: ${{ github.event.pull_request.head.repo.full_name }} - name: Setup .NET - uses: actions/setup-dotnet@aa983c550dfda0d1722b6ac6aed55724ffacc6d3 # v3.1.0 + uses: actions/setup-dotnet@3447fd6a9f9e57506b15f895c5b76d3b197dc7c2 # v3.2.0 with: dotnet-version: '7.0.x' - name: Generate openapi.json @@ -51,7 +51,7 @@ jobs: ANCESTOR_REF=$(git merge-base upstream/${{ github.base_ref }} origin/${{ github.head_ref }}) git checkout --progress --force $ANCESTOR_REF - name: Setup .NET - uses: actions/setup-dotnet@aa983c550dfda0d1722b6ac6aed55724ffacc6d3 # v3.1.0 + uses: actions/setup-dotnet@3447fd6a9f9e57506b15f895c5b76d3b197dc7c2 # v3.2.0 with: dotnet-version: '7.0.x' - name: Generate openapi.json diff --git a/Directory.Packages.props b/Directory.Packages.props index bb5b72d21..cd26f74a9 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -17,7 +17,7 @@ <PackageVersion Include="Diacritics" Version="3.3.18" /> <PackageVersion Include="DiscUtils.Udf" Version="0.16.13" /> <PackageVersion Include="DotNet.Glob" Version="3.1.3" /> - <PackageVersion Include="EFCoreSecondLevelCacheInterceptor" Version="3.9.1" /> + <PackageVersion Include="EFCoreSecondLevelCacheInterceptor" Version="3.9.2" /> <PackageVersion Include="FsCheck.Xunit" Version="2.16.5" /> <PackageVersion Include="Jellyfin.XmlTv" Version="10.8.0" /> <PackageVersion Include="libse" Version="3.6.13" /> @@ -52,7 +52,7 @@ <PackageVersion Include="Moq" Version="4.18.4" /> <PackageVersion Include="NEbml" Version="0.11.0" /> <PackageVersion Include="Newtonsoft.Json" Version="13.0.3" /> - <PackageVersion Include="PlaylistsNET" Version="1.3.2" /> + <PackageVersion Include="PlaylistsNET" Version="1.4.0" /> <PackageVersion Include="prometheus-net.AspNetCore" Version="8.0.0" /> <PackageVersion Include="prometheus-net.DotNetRuntime" Version="4.4.0" /> <PackageVersion Include="prometheus-net" Version="8.0.0" /> diff --git a/Emby.Server.Implementations/Localization/Core/lt-LT.json b/Emby.Server.Implementations/Localization/Core/lt-LT.json index e1c937b6c..ce8d8fc32 100644 --- a/Emby.Server.Implementations/Localization/Core/lt-LT.json +++ b/Emby.Server.Implementations/Localization/Core/lt-LT.json @@ -20,9 +20,9 @@ "HeaderFavoriteAlbums": "Mėgstami Albumai", "HeaderFavoriteArtists": "Mėgstami Atlikėjai", "HeaderFavoriteEpisodes": "Mėgstamiausios serijos", - "HeaderFavoriteShows": "Mėgstamiausi serialai", - "HeaderFavoriteSongs": "Mėgstamos dainos", - "HeaderLiveTV": "TV gyvai", + "HeaderFavoriteShows": "Mėgstamiausios TV Laidos", + "HeaderFavoriteSongs": "Mėgstamos Dainos", + "HeaderLiveTV": "Tiesioginė TV", "HeaderNextUp": "Toliau eilėje", "HeaderRecordingGroups": "Įrašų grupės", "HomeVideos": "Namų vaizdo įrašai", diff --git a/Jellyfin.Api/Controllers/UserController.cs b/Jellyfin.Api/Controllers/UserController.cs index e49528867..530bd9603 100644 --- a/Jellyfin.Api/Controllers/UserController.cs +++ b/Jellyfin.Api/Controllers/UserController.cs @@ -323,36 +323,16 @@ public class UserController : BaseJellyfinApiController /// <response code="404">User not found.</response> /// <returns>A <see cref="NoContentResult"/> indicating success or a <see cref="ForbidResult"/> or a <see cref="NotFoundResult"/> on failure.</returns> [HttpPost("{userId}/EasyPassword")] + [Obsolete("Use Quick Connect instead")] [Authorize] [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status403Forbidden)] [ProducesResponseType(StatusCodes.Status404NotFound)] - public async Task<ActionResult> UpdateUserEasyPassword( + public ActionResult UpdateUserEasyPassword( [FromRoute, Required] Guid userId, [FromBody, Required] UpdateUserEasyPassword request) { - if (!RequestHelpers.AssertCanUpdateUser(_userManager, User, userId, true)) - { - return StatusCode(StatusCodes.Status403Forbidden, "User is not allowed to update the easy password."); - } - - var user = _userManager.GetUserById(userId); - - if (user is null) - { - return NotFound("User not found"); - } - - if (request.ResetPassword) - { - await _userManager.ResetEasyPassword(user).ConfigureAwait(false); - } - else - { - await _userManager.ChangeEasyPassword(user, request.NewPw ?? string.Empty, request.NewPassword ?? string.Empty).ConfigureAwait(false); - } - - return NoContent(); + return Forbid(); } /// <summary> diff --git a/Jellyfin.Data/Entities/User.cs b/Jellyfin.Data/Entities/User.cs index 606e1b542..58ddaaf83 100644 --- a/Jellyfin.Data/Entities/User.cs +++ b/Jellyfin.Data/Entities/User.cs @@ -92,16 +92,6 @@ namespace Jellyfin.Data.Entities public string? Password { get; set; } /// <summary> - /// Gets or sets the user's easy password, or <c>null</c> if none is set. - /// </summary> - /// <remarks> - /// Max length = 65535. - /// </remarks> - [MaxLength(65535)] - [StringLength(65535)] - public string? EasyPassword { get; set; } - - /// <summary> /// Gets or sets a value indicating whether the user must update their password. /// </summary> /// <remarks> diff --git a/Jellyfin.Server.Implementations/Migrations/20230526173516_RemoveEasyPassword.Designer.cs b/Jellyfin.Server.Implementations/Migrations/20230526173516_RemoveEasyPassword.Designer.cs new file mode 100644 index 000000000..00ccd9f0f --- /dev/null +++ b/Jellyfin.Server.Implementations/Migrations/20230526173516_RemoveEasyPassword.Designer.cs @@ -0,0 +1,650 @@ +// <auto-generated /> +using System; +using Jellyfin.Server.Implementations; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace Jellyfin.Server.Implementations.Migrations +{ + [DbContext(typeof(JellyfinDbContext))] + [Migration("20230526173516_RemoveEasyPassword")] + partial class RemoveEasyPassword + { + /// <inheritdoc /> + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "7.0.5"); + + modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property<int>("DayOfWeek") + .HasColumnType("INTEGER"); + + b.Property<double>("EndHour") + .HasColumnType("REAL"); + + b.Property<double>("StartHour") + .HasColumnType("REAL"); + + b.Property<Guid>("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AccessSchedules"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ActivityLog", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property<DateTime>("DateCreated") + .HasColumnType("TEXT"); + + b.Property<string>("ItemId") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property<int>("LogSeverity") + .HasColumnType("INTEGER"); + + b.Property<string>("Name") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property<string>("Overview") + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property<uint>("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property<string>("ShortOverview") + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property<string>("Type") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property<Guid>("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("DateCreated"); + + b.ToTable("ActivityLogs"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.CustomItemDisplayPreferences", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property<string>("Client") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property<Guid>("ItemId") + .HasColumnType("TEXT"); + + b.Property<string>("Key") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property<Guid>("UserId") + .HasColumnType("TEXT"); + + b.Property<string>("Value") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "ItemId", "Client", "Key") + .IsUnique(); + + b.ToTable("CustomItemDisplayPreferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property<int>("ChromecastVersion") + .HasColumnType("INTEGER"); + + b.Property<string>("Client") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property<string>("DashboardTheme") + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property<bool>("EnableNextVideoInfoOverlay") + .HasColumnType("INTEGER"); + + b.Property<int?>("IndexBy") + .HasColumnType("INTEGER"); + + b.Property<Guid>("ItemId") + .HasColumnType("TEXT"); + + b.Property<int>("ScrollDirection") + .HasColumnType("INTEGER"); + + b.Property<bool>("ShowBackdrop") + .HasColumnType("INTEGER"); + + b.Property<bool>("ShowSidebar") + .HasColumnType("INTEGER"); + + b.Property<int>("SkipBackwardLength") + .HasColumnType("INTEGER"); + + b.Property<int>("SkipForwardLength") + .HasColumnType("INTEGER"); + + b.Property<string>("TvHome") + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property<Guid>("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "ItemId", "Client") + .IsUnique(); + + b.ToTable("DisplayPreferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property<int>("DisplayPreferencesId") + .HasColumnType("INTEGER"); + + b.Property<int>("Order") + .HasColumnType("INTEGER"); + + b.Property<int>("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("DisplayPreferencesId"); + + b.ToTable("HomeSection"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property<DateTime>("LastModified") + .HasColumnType("TEXT"); + + b.Property<string>("Path") + .IsRequired() + .HasMaxLength(512) + .HasColumnType("TEXT"); + + b.Property<Guid?>("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("ImageInfos"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property<string>("Client") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property<int?>("IndexBy") + .HasColumnType("INTEGER"); + + b.Property<Guid>("ItemId") + .HasColumnType("TEXT"); + + b.Property<bool>("RememberIndexing") + .HasColumnType("INTEGER"); + + b.Property<bool>("RememberSorting") + .HasColumnType("INTEGER"); + + b.Property<string>("SortBy") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.Property<int>("SortOrder") + .HasColumnType("INTEGER"); + + b.Property<Guid>("UserId") + .HasColumnType("TEXT"); + + b.Property<int>("ViewType") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("ItemDisplayPreferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property<int>("Kind") + .HasColumnType("INTEGER"); + + b.Property<Guid?>("Permission_Permissions_Guid") + .HasColumnType("TEXT"); + + b.Property<uint>("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property<Guid?>("UserId") + .HasColumnType("TEXT"); + + b.Property<bool>("Value") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "Kind") + .IsUnique() + .HasFilter("[UserId] IS NOT NULL"); + + b.ToTable("Permissions"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property<int>("Kind") + .HasColumnType("INTEGER"); + + b.Property<Guid?>("Preference_Preferences_Guid") + .HasColumnType("TEXT"); + + b.Property<uint>("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property<Guid?>("UserId") + .HasColumnType("TEXT"); + + b.Property<string>("Value") + .IsRequired() + .HasMaxLength(65535) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "Kind") + .IsUnique() + .HasFilter("[UserId] IS NOT NULL"); + + b.ToTable("Preferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Security.ApiKey", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property<string>("AccessToken") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property<DateTime>("DateCreated") + .HasColumnType("TEXT"); + + b.Property<DateTime>("DateLastActivity") + .HasColumnType("TEXT"); + + b.Property<string>("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("AccessToken") + .IsUnique(); + + b.ToTable("ApiKeys"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Security.Device", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property<string>("AccessToken") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property<string>("AppName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.Property<string>("AppVersion") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property<DateTime>("DateCreated") + .HasColumnType("TEXT"); + + b.Property<DateTime>("DateLastActivity") + .HasColumnType("TEXT"); + + b.Property<DateTime>("DateModified") + .HasColumnType("TEXT"); + + b.Property<string>("DeviceId") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property<string>("DeviceName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.Property<bool>("IsActive") + .HasColumnType("INTEGER"); + + b.Property<Guid>("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("DeviceId"); + + b.HasIndex("AccessToken", "DateLastActivity"); + + b.HasIndex("DeviceId", "DateLastActivity"); + + b.HasIndex("UserId", "DeviceId"); + + b.ToTable("Devices"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Security.DeviceOptions", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property<string>("CustomName") + .HasColumnType("TEXT"); + + b.Property<string>("DeviceId") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("DeviceId") + .IsUnique(); + + b.ToTable("DeviceOptions"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.User", b => + { + b.Property<Guid>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property<string>("AudioLanguagePreference") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property<string>("AuthenticationProviderId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property<bool>("DisplayCollectionsView") + .HasColumnType("INTEGER"); + + b.Property<bool>("DisplayMissingEpisodes") + .HasColumnType("INTEGER"); + + b.Property<bool>("EnableAutoLogin") + .HasColumnType("INTEGER"); + + b.Property<bool>("EnableLocalPassword") + .HasColumnType("INTEGER"); + + b.Property<bool>("EnableNextEpisodeAutoPlay") + .HasColumnType("INTEGER"); + + b.Property<bool>("EnableUserPreferenceAccess") + .HasColumnType("INTEGER"); + + b.Property<bool>("HidePlayedInLatest") + .HasColumnType("INTEGER"); + + b.Property<long>("InternalId") + .HasColumnType("INTEGER"); + + b.Property<int>("InvalidLoginAttemptCount") + .HasColumnType("INTEGER"); + + b.Property<DateTime?>("LastActivityDate") + .HasColumnType("TEXT"); + + b.Property<DateTime?>("LastLoginDate") + .HasColumnType("TEXT"); + + b.Property<int?>("LoginAttemptsBeforeLockout") + .HasColumnType("INTEGER"); + + b.Property<int>("MaxActiveSessions") + .HasColumnType("INTEGER"); + + b.Property<int?>("MaxParentalAgeRating") + .HasColumnType("INTEGER"); + + b.Property<bool>("MustUpdatePassword") + .HasColumnType("INTEGER"); + + b.Property<string>("Password") + .HasMaxLength(65535) + .HasColumnType("TEXT"); + + b.Property<string>("PasswordResetProviderId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property<bool>("PlayDefaultAudioTrack") + .HasColumnType("INTEGER"); + + b.Property<bool>("RememberAudioSelections") + .HasColumnType("INTEGER"); + + b.Property<bool>("RememberSubtitleSelections") + .HasColumnType("INTEGER"); + + b.Property<int?>("RemoteClientBitrateLimit") + .HasColumnType("INTEGER"); + + b.Property<uint>("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property<string>("SubtitleLanguagePreference") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property<int>("SubtitleMode") + .HasColumnType("INTEGER"); + + b.Property<int>("SyncPlayAccess") + .HasColumnType("INTEGER"); + + b.Property<string>("Username") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT") + .UseCollation("NOCASE"); + + b.HasKey("Id"); + + b.HasIndex("Username") + .IsUnique(); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("AccessSchedules") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("DisplayPreferences") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => + { + b.HasOne("Jellyfin.Data.Entities.DisplayPreferences", null) + .WithMany("HomeSections") + .HasForeignKey("DisplayPreferencesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithOne("ProfileImage") + .HasForeignKey("Jellyfin.Data.Entities.ImageInfo", "UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("ItemDisplayPreferences") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("Permissions") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("Preferences") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Security.Device", b => + { + b.HasOne("Jellyfin.Data.Entities.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => + { + b.Navigation("HomeSections"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.User", b => + { + b.Navigation("AccessSchedules"); + + b.Navigation("DisplayPreferences"); + + b.Navigation("ItemDisplayPreferences"); + + b.Navigation("Permissions"); + + b.Navigation("Preferences"); + + b.Navigation("ProfileImage"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Jellyfin.Server.Implementations/Migrations/20230526173516_RemoveEasyPassword.cs b/Jellyfin.Server.Implementations/Migrations/20230526173516_RemoveEasyPassword.cs new file mode 100644 index 000000000..9496ff3c0 --- /dev/null +++ b/Jellyfin.Server.Implementations/Migrations/20230526173516_RemoveEasyPassword.cs @@ -0,0 +1,164 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Jellyfin.Server.Implementations.Migrations +{ + /// <inheritdoc /> + public partial class RemoveEasyPassword : Migration + { + /// <inheritdoc /> + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "EasyPassword", + schema: "jellyfin", + table: "Users"); + + migrationBuilder.RenameTable( + name: "Users", + schema: "jellyfin", + newName: "Users"); + + migrationBuilder.RenameTable( + name: "Preferences", + schema: "jellyfin", + newName: "Preferences"); + + migrationBuilder.RenameTable( + name: "Permissions", + schema: "jellyfin", + newName: "Permissions"); + + migrationBuilder.RenameTable( + name: "ItemDisplayPreferences", + schema: "jellyfin", + newName: "ItemDisplayPreferences"); + + migrationBuilder.RenameTable( + name: "ImageInfos", + schema: "jellyfin", + newName: "ImageInfos"); + + migrationBuilder.RenameTable( + name: "HomeSection", + schema: "jellyfin", + newName: "HomeSection"); + + migrationBuilder.RenameTable( + name: "DisplayPreferences", + schema: "jellyfin", + newName: "DisplayPreferences"); + + migrationBuilder.RenameTable( + name: "Devices", + schema: "jellyfin", + newName: "Devices"); + + migrationBuilder.RenameTable( + name: "DeviceOptions", + schema: "jellyfin", + newName: "DeviceOptions"); + + migrationBuilder.RenameTable( + name: "CustomItemDisplayPreferences", + schema: "jellyfin", + newName: "CustomItemDisplayPreferences"); + + migrationBuilder.RenameTable( + name: "ApiKeys", + schema: "jellyfin", + newName: "ApiKeys"); + + migrationBuilder.RenameTable( + name: "ActivityLogs", + schema: "jellyfin", + newName: "ActivityLogs"); + + migrationBuilder.RenameTable( + name: "AccessSchedules", + schema: "jellyfin", + newName: "AccessSchedules"); + } + + /// <inheritdoc /> + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.EnsureSchema( + name: "jellyfin"); + + migrationBuilder.RenameTable( + name: "Users", + newName: "Users", + newSchema: "jellyfin"); + + migrationBuilder.RenameTable( + name: "Preferences", + newName: "Preferences", + newSchema: "jellyfin"); + + migrationBuilder.RenameTable( + name: "Permissions", + newName: "Permissions", + newSchema: "jellyfin"); + + migrationBuilder.RenameTable( + name: "ItemDisplayPreferences", + newName: "ItemDisplayPreferences", + newSchema: "jellyfin"); + + migrationBuilder.RenameTable( + name: "ImageInfos", + newName: "ImageInfos", + newSchema: "jellyfin"); + + migrationBuilder.RenameTable( + name: "HomeSection", + newName: "HomeSection", + newSchema: "jellyfin"); + + migrationBuilder.RenameTable( + name: "DisplayPreferences", + newName: "DisplayPreferences", + newSchema: "jellyfin"); + + migrationBuilder.RenameTable( + name: "Devices", + newName: "Devices", + newSchema: "jellyfin"); + + migrationBuilder.RenameTable( + name: "DeviceOptions", + newName: "DeviceOptions", + newSchema: "jellyfin"); + + migrationBuilder.RenameTable( + name: "CustomItemDisplayPreferences", + newName: "CustomItemDisplayPreferences", + newSchema: "jellyfin"); + + migrationBuilder.RenameTable( + name: "ApiKeys", + newName: "ApiKeys", + newSchema: "jellyfin"); + + migrationBuilder.RenameTable( + name: "ActivityLogs", + newName: "ActivityLogs", + newSchema: "jellyfin"); + + migrationBuilder.RenameTable( + name: "AccessSchedules", + newName: "AccessSchedules", + newSchema: "jellyfin"); + + migrationBuilder.AddColumn<string>( + name: "EasyPassword", + schema: "jellyfin", + table: "Users", + type: "TEXT", + maxLength: 65535, + nullable: true); + } + } +} diff --git a/Jellyfin.Server.Implementations/Migrations/JellyfinDbModelSnapshot.cs b/Jellyfin.Server.Implementations/Migrations/JellyfinDbModelSnapshot.cs index dd5f7f012..d23508096 100644 --- a/Jellyfin.Server.Implementations/Migrations/JellyfinDbModelSnapshot.cs +++ b/Jellyfin.Server.Implementations/Migrations/JellyfinDbModelSnapshot.cs @@ -15,9 +15,7 @@ namespace Jellyfin.Server.Implementations.Migrations protected override void BuildModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 - modelBuilder - .HasDefaultSchema("jellyfin") - .HasAnnotation("ProductVersion", "6.0.9"); + modelBuilder.HasAnnotation("ProductVersion", "7.0.5"); modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => { @@ -41,7 +39,7 @@ namespace Jellyfin.Server.Implementations.Migrations b.HasIndex("UserId"); - b.ToTable("AccessSchedules", "jellyfin"); + b.ToTable("AccessSchedules"); }); modelBuilder.Entity("Jellyfin.Data.Entities.ActivityLog", b => @@ -89,7 +87,7 @@ namespace Jellyfin.Server.Implementations.Migrations b.HasIndex("DateCreated"); - b.ToTable("ActivityLogs", "jellyfin"); + b.ToTable("ActivityLogs"); }); modelBuilder.Entity("Jellyfin.Data.Entities.CustomItemDisplayPreferences", b => @@ -121,7 +119,7 @@ namespace Jellyfin.Server.Implementations.Migrations b.HasIndex("UserId", "ItemId", "Client", "Key") .IsUnique(); - b.ToTable("CustomItemDisplayPreferences", "jellyfin"); + b.ToTable("CustomItemDisplayPreferences"); }); modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => @@ -178,7 +176,7 @@ namespace Jellyfin.Server.Implementations.Migrations b.HasIndex("UserId", "ItemId", "Client") .IsUnique(); - b.ToTable("DisplayPreferences", "jellyfin"); + b.ToTable("DisplayPreferences"); }); modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => @@ -200,7 +198,7 @@ namespace Jellyfin.Server.Implementations.Migrations b.HasIndex("DisplayPreferencesId"); - b.ToTable("HomeSection", "jellyfin"); + b.ToTable("HomeSection"); }); modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => @@ -225,7 +223,7 @@ namespace Jellyfin.Server.Implementations.Migrations b.HasIndex("UserId") .IsUnique(); - b.ToTable("ImageInfos", "jellyfin"); + b.ToTable("ImageInfos"); }); modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => @@ -269,7 +267,7 @@ namespace Jellyfin.Server.Implementations.Migrations b.HasIndex("UserId"); - b.ToTable("ItemDisplayPreferences", "jellyfin"); + b.ToTable("ItemDisplayPreferences"); }); modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => @@ -300,7 +298,7 @@ namespace Jellyfin.Server.Implementations.Migrations .IsUnique() .HasFilter("[UserId] IS NOT NULL"); - b.ToTable("Permissions", "jellyfin"); + b.ToTable("Permissions"); }); modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => @@ -333,7 +331,7 @@ namespace Jellyfin.Server.Implementations.Migrations .IsUnique() .HasFilter("[UserId] IS NOT NULL"); - b.ToTable("Preferences", "jellyfin"); + b.ToTable("Preferences"); }); modelBuilder.Entity("Jellyfin.Data.Entities.Security.ApiKey", b => @@ -362,7 +360,7 @@ namespace Jellyfin.Server.Implementations.Migrations b.HasIndex("AccessToken") .IsUnique(); - b.ToTable("ApiKeys", "jellyfin"); + b.ToTable("ApiKeys"); }); modelBuilder.Entity("Jellyfin.Data.Entities.Security.Device", b => @@ -420,7 +418,7 @@ namespace Jellyfin.Server.Implementations.Migrations b.HasIndex("UserId", "DeviceId"); - b.ToTable("Devices", "jellyfin"); + b.ToTable("Devices"); }); modelBuilder.Entity("Jellyfin.Data.Entities.Security.DeviceOptions", b => @@ -441,7 +439,7 @@ namespace Jellyfin.Server.Implementations.Migrations b.HasIndex("DeviceId") .IsUnique(); - b.ToTable("DeviceOptions", "jellyfin"); + b.ToTable("DeviceOptions"); }); modelBuilder.Entity("Jellyfin.Data.Entities.User", b => @@ -465,10 +463,6 @@ namespace Jellyfin.Server.Implementations.Migrations b.Property<bool>("DisplayMissingEpisodes") .HasColumnType("INTEGER"); - b.Property<string>("EasyPassword") - .HasMaxLength(65535) - .HasColumnType("TEXT"); - b.Property<bool>("EnableAutoLogin") .HasColumnType("INTEGER"); @@ -554,7 +548,7 @@ namespace Jellyfin.Server.Implementations.Migrations b.HasIndex("Username") .IsUnique(); - b.ToTable("Users", "jellyfin"); + b.ToTable("Users"); }); modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => diff --git a/Jellyfin.Server.Implementations/Users/DefaultPasswordResetProvider.cs b/Jellyfin.Server.Implementations/Users/DefaultPasswordResetProvider.cs index 960195467..cefbd0624 100644 --- a/Jellyfin.Server.Implementations/Users/DefaultPasswordResetProvider.cs +++ b/Jellyfin.Server.Implementations/Users/DefaultPasswordResetProvider.cs @@ -114,8 +114,6 @@ namespace Jellyfin.Server.Implementations.Users await JsonSerializer.SerializeAsync(fileStream, spr).ConfigureAwait(false); } - user.EasyPassword = pin; - return new ForgotPasswordResult { Action = ForgotPasswordAction.PinCode, diff --git a/Jellyfin.Server.Implementations/Users/UserManager.cs b/Jellyfin.Server.Implementations/Users/UserManager.cs index 04c3d8a70..1d03baa4c 100644 --- a/Jellyfin.Server.Implementations/Users/UserManager.cs +++ b/Jellyfin.Server.Implementations/Users/UserManager.cs @@ -269,12 +269,6 @@ namespace Jellyfin.Server.Implementations.Users } /// <inheritdoc/> - public Task ResetEasyPassword(User user) - { - return ChangeEasyPassword(user, string.Empty, null); - } - - /// <inheritdoc/> public async Task ChangePassword(User user, string newPassword) { ArgumentNullException.ThrowIfNull(user); @@ -290,25 +284,6 @@ namespace Jellyfin.Server.Implementations.Users } /// <inheritdoc/> - public async Task ChangeEasyPassword(User user, string newPassword, string? newPasswordSha1) - { - if (newPassword is not null) - { - newPasswordSha1 = _cryptoProvider.CreatePasswordHash(newPassword).ToString(); - } - - if (string.IsNullOrWhiteSpace(newPasswordSha1)) - { - throw new ArgumentNullException(nameof(newPasswordSha1)); - } - - user.EasyPassword = newPasswordSha1; - await UpdateUserAsync(user).ConfigureAwait(false); - - await _eventManager.PublishAsync(new UserPasswordChangedEventArgs(user)).ConfigureAwait(false); - } - - /// <inheritdoc/> public UserDto GetUserDto(User user, string? remoteEndPoint = null) { var hasPassword = GetAuthenticationProvider(user).HasPassword(user); @@ -319,7 +294,6 @@ namespace Jellyfin.Server.Implementations.Users ServerId = _appHost.SystemId, HasPassword = hasPassword, HasConfiguredPassword = hasPassword, - HasConfiguredEasyPassword = !string.IsNullOrEmpty(user.EasyPassword), EnableAutoLogin = user.EnableAutoLogin, LastLoginDate = user.LastLoginDate, LastActivityDate = user.LastActivityDate, @@ -836,16 +810,6 @@ namespace Jellyfin.Server.Implementations.Users } } - if (!success - && _networkManager.IsInLocalNetwork(remoteEndPoint) - && user?.EnableLocalPassword == true - && !string.IsNullOrEmpty(user.EasyPassword)) - { - // Check easy password - var passwordHash = PasswordHash.Parse(user.EasyPassword); - success = _cryptoProvider.Verify(passwordHash, password); - } - return (authenticationProvider, username, success); } diff --git a/Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs b/Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs index 9bf1e6b80..0186500a1 100644 --- a/Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs +++ b/Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs @@ -127,7 +127,6 @@ namespace Jellyfin.Server.Migrations.Routines RememberSubtitleSelections = config.RememberSubtitleSelections, SubtitleLanguagePreference = config.SubtitleLanguagePreference, Password = mockup.Password, - EasyPassword = mockup.EasyPassword, LastLoginDate = mockup.LastLoginDate, LastActivityDate = mockup.LastActivityDate }; diff --git a/MediaBrowser.Controller/Library/IUserManager.cs b/MediaBrowser.Controller/Library/IUserManager.cs index 37b4afcf3..6d6a532db 100644 --- a/MediaBrowser.Controller/Library/IUserManager.cs +++ b/MediaBrowser.Controller/Library/IUserManager.cs @@ -97,13 +97,6 @@ namespace MediaBrowser.Controller.Library Task ResetPassword(User user); /// <summary> - /// Resets the easy password. - /// </summary> - /// <param name="user">The user.</param> - /// <returns>Task.</returns> - Task ResetEasyPassword(User user); - - /// <summary> /// Changes the password. /// </summary> /// <param name="user">The user.</param> @@ -112,15 +105,6 @@ namespace MediaBrowser.Controller.Library Task ChangePassword(User user, string newPassword); /// <summary> - /// Changes the easy password. - /// </summary> - /// <param name="user">The user.</param> - /// <param name="newPassword">New password to use.</param> - /// <param name="newPasswordSha1">Hash of new password.</param> - /// <returns>Task.</returns> - Task ChangeEasyPassword(User user, string newPassword, string newPasswordSha1); - - /// <summary> /// Gets the user dto. /// </summary> /// <param name="user">The user.</param> diff --git a/MediaBrowser.Model/Dto/UserDto.cs b/MediaBrowser.Model/Dto/UserDto.cs index 256d7b10f..05019741e 100644 --- a/MediaBrowser.Model/Dto/UserDto.cs +++ b/MediaBrowser.Model/Dto/UserDto.cs @@ -66,6 +66,7 @@ namespace MediaBrowser.Model.Dto /// Gets or sets a value indicating whether this instance has configured easy password. /// </summary> /// <value><c>true</c> if this instance has configured easy password; otherwise, <c>false</c>.</value> + [Obsolete("Easy Password has been replaced with Quick Connect")] public bool HasConfiguredEasyPassword { get; set; } /// <summary> |
