MigrateAuthenticationDb.cs 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using Emby.Server.Implementations.Data;
  5. using Jellyfin.Data.Entities.Security;
  6. using Jellyfin.Server.Implementations;
  7. using MediaBrowser.Controller;
  8. using Microsoft.Extensions.Logging;
  9. using SQLitePCL.pretty;
  10. namespace Jellyfin.Server.Migrations.Routines
  11. {
  12. /// <summary>
  13. /// A migration that moves data from the authentication database into the new schema.
  14. /// </summary>
  15. public class MigrateAuthenticationDb : IMigrationRoutine
  16. {
  17. private const string DbFilename = "authentication.db";
  18. private readonly ILogger<MigrateAuthenticationDb> _logger;
  19. private readonly JellyfinDbProvider _dbProvider;
  20. private readonly IServerApplicationPaths _appPaths;
  21. /// <summary>
  22. /// Initializes a new instance of the <see cref="MigrateAuthenticationDb"/> class.
  23. /// </summary>
  24. /// <param name="logger">The logger.</param>
  25. /// <param name="dbProvider">The database provider.</param>
  26. /// <param name="appPaths">The server application paths.</param>
  27. public MigrateAuthenticationDb(ILogger<MigrateAuthenticationDb> logger, JellyfinDbProvider dbProvider, IServerApplicationPaths appPaths)
  28. {
  29. _logger = logger;
  30. _dbProvider = dbProvider;
  31. _appPaths = appPaths;
  32. }
  33. /// <inheritdoc />
  34. public Guid Id => Guid.Parse("5BD72F41-E6F3-4F60-90AA-09869ABE0E22");
  35. /// <inheritdoc />
  36. public string Name => "MigrateAuthenticationDatabase";
  37. /// <inheritdoc />
  38. public bool PerformOnNewInstall => false;
  39. /// <inheritdoc />
  40. public void Perform()
  41. {
  42. var dataPath = _appPaths.DataPath;
  43. using (var connection = SQLite3.Open(
  44. Path.Combine(dataPath, DbFilename),
  45. ConnectionFlags.ReadOnly,
  46. null))
  47. {
  48. using var dbContext = _dbProvider.CreateContext();
  49. var authenticatedDevices = connection.Query("SELECT * FROM Tokens");
  50. foreach (var row in authenticatedDevices)
  51. {
  52. var dateCreatedStr = row[9].ToString();
  53. _ = DateTime.TryParse(dateCreatedStr, out var dateCreated);
  54. var dateLastActivityStr = row[10].ToString();
  55. _ = DateTime.TryParse(dateLastActivityStr, out var dateLastActivity);
  56. if (row[6].IsDbNull())
  57. {
  58. dbContext.ApiKeys.Add(new ApiKey(row[3].ToString())
  59. {
  60. AccessToken = row[1].ToString(),
  61. DateCreated = dateCreated,
  62. DateLastActivity = dateLastActivity
  63. });
  64. }
  65. else
  66. {
  67. dbContext.Devices.Add(new Device(
  68. new Guid(row[6].ToString()),
  69. row[3].ToString(),
  70. row[4].ToString(),
  71. row[5].ToString(),
  72. row[2].ToString())
  73. {
  74. AccessToken = row[1].ToString(),
  75. IsActive = row[8].ToBool(),
  76. DateCreated = dateCreated,
  77. DateLastActivity = dateLastActivity
  78. });
  79. }
  80. }
  81. var deviceOptions = connection.Query("SELECT * FROM Devices");
  82. var deviceIds = new HashSet<string>();
  83. foreach (var row in deviceOptions)
  84. {
  85. if (row[2].IsDbNull())
  86. {
  87. continue;
  88. }
  89. var deviceId = row[2].ToString();
  90. if (deviceIds.Contains(deviceId))
  91. {
  92. continue;
  93. }
  94. deviceIds.Add(deviceId);
  95. dbContext.DeviceOptions.Add(new DeviceOptions(deviceId)
  96. {
  97. CustomName = row[1].IsDbNull() ? null : row[1].ToString()
  98. });
  99. }
  100. dbContext.SaveChanges();
  101. }
  102. try
  103. {
  104. File.Move(Path.Combine(dataPath, DbFilename), Path.Combine(dataPath, DbFilename + ".old"));
  105. var journalPath = Path.Combine(dataPath, DbFilename + "-journal");
  106. if (File.Exists(journalPath))
  107. {
  108. File.Move(journalPath, Path.Combine(dataPath, DbFilename + ".old-journal"));
  109. }
  110. }
  111. catch (IOException e)
  112. {
  113. _logger.LogError(e, "Error renaming legacy activity log database to 'authentication.db.old'");
  114. }
  115. }
  116. }
  117. }