From e73ae99e388bdc4e1ae349e24fed48ebe59d3140 Mon Sep 17 00:00:00 2001 From: flightlevel Date: Wed, 30 May 2018 21:43:58 +1000 Subject: [PATCH] Implement AspNetCore.DataProtection to replace DPAPI --- src/Jackett.Server/Program.cs | 16 +++++++---- .../Services/ProtectionService.cs | 27 ++++++++++++++++--- src/Jackett.Server/Startup.cs | 8 ++++++ 3 files changed, 43 insertions(+), 8 deletions(-) diff --git a/src/Jackett.Server/Program.cs b/src/Jackett.Server/Program.cs index d5f941aff..b5d0c7091 100644 --- a/src/Jackett.Server/Program.cs +++ b/src/Jackett.Server/Program.cs @@ -12,6 +12,7 @@ using Microsoft.Extensions.Configuration; using NLog; using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Runtime.InteropServices; @@ -34,13 +35,13 @@ namespace Jackett.Server }); var runtimeDictionary = new Dictionary(); - RuntimeSettings r = new RuntimeSettings(); + RuntimeSettings runtimeSettings = new RuntimeSettings(); ConsoleOptions consoleOptions = new ConsoleOptions(); optionsResult.WithParsed(options => { - r = options.ToRunTimeSettings(); + runtimeSettings = options.ToRunTimeSettings(); consoleOptions = options; - runtimeDictionary = GetValues(r); + runtimeDictionary = GetValues(runtimeSettings); }); var builder = new ConfigurationBuilder(); @@ -50,8 +51,8 @@ namespace Jackett.Server //hack TODO: Get the configuration without any DI var containerBuilder = new ContainerBuilder(); - Initialisation.SetupLogging(r, containerBuilder); - containerBuilder.RegisterModule(new JackettModule(r)); + Initialisation.SetupLogging(runtimeSettings, containerBuilder); + containerBuilder.RegisterModule(new JackettModule(runtimeSettings)); containerBuilder.RegisterType().As(); containerBuilder.RegisterType().As(); containerBuilder.RegisterType().As(); @@ -63,6 +64,11 @@ namespace Jackett.Server IServerService serverService = tempContainer.Resolve(); Int32.TryParse(serverConfig.Port.ToString(), out Int32 configPort); + DirectoryInfo dataProtectionFolder = new DirectoryInfo(Path.Combine(runtimeSettings.DataFolder, "DataProtection")); + if (!dataProtectionFolder.Exists) + { + dataProtectionFolder.Create(); + } // Override port if (consoleOptions.Port != 0) diff --git a/src/Jackett.Server/Services/ProtectionService.cs b/src/Jackett.Server/Services/ProtectionService.cs index deaacce0b..cde6d3b9b 100644 --- a/src/Jackett.Server/Services/ProtectionService.cs +++ b/src/Jackett.Server/Services/ProtectionService.cs @@ -8,6 +8,7 @@ using Jackett.Common; using Jackett.Common.Models.Config; using Jackett.Common.Services.Interfaces; using Jackett.Common.Utils; +using Microsoft.AspNetCore.DataProtection; namespace Jackett.Server.Services { @@ -18,18 +19,38 @@ namespace Jackett.Server.Services private const string JACKETT_KEY = "JACKETT_KEY"; const string APPLICATION_KEY = "Dvz66r3n8vhTGip2/quiw5ISyM37f7L2iOdupzdKmzkvXGhAgQiWK+6F+4qpxjPVNks1qO7LdWuVqRlzgLzeW8mChC6JnBMUS1Fin4N2nS9lh4XPuCZ1che75xO92Nk2vyXUo9KSFG1hvEszAuLfG2Mcg1r0sVyVXd2gQDU/TbY="; private byte[] _instanceKey; + IDataProtector _protector = null; - public ProtectionService(ServerConfig config) + public ProtectionService(ServerConfig config, IDataProtectionProvider provider = null) { - if (System.Environment.OSVersion.Platform == PlatformID.Unix) + if (Environment.OSVersion.Platform == PlatformID.Unix) { // We should not be running as root and will only have access to the local store. PROTECTION_SCOPE = DataProtectionScope.CurrentUser; } _instanceKey = Encoding.UTF8.GetBytes(config.InstanceId); + + if (provider != null) + { + var jackettKey = Environment.GetEnvironmentVariable(JACKETT_KEY); + string purpose = string.IsNullOrEmpty(jackettKey) ? APPLICATION_KEY : jackettKey.ToString(); + + _protector = provider.CreateProtector(purpose); + } + } public string Protect(string plainText) + { + return _protector.Protect(plainText); + } + + public string UnProtect(string plainText) + { + return _protector.Unprotect(plainText); + } + + public string LegacyProtect(string plainText) { var jackettKey = Environment.GetEnvironmentVariable(JACKETT_KEY); @@ -43,7 +64,7 @@ namespace Jackett.Server.Services } } - public string UnProtect(string plainText) + public string LegacyUnProtect(string plainText) { var jackettKey = Environment.GetEnvironmentVariable(JACKETT_KEY); diff --git a/src/Jackett.Server/Startup.cs b/src/Jackett.Server/Startup.cs index 5d2cdca70..e7a6120c7 100644 --- a/src/Jackett.Server/Startup.cs +++ b/src/Jackett.Server/Startup.cs @@ -8,6 +8,7 @@ using Jackett.Server.Services; using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.DataProtection; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; @@ -18,6 +19,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.FileProviders; using Newtonsoft.Json.Serialization; using System; +using System.IO; using System.Text; namespace Jackett.Server @@ -62,6 +64,12 @@ namespace Jackett.Server RuntimeSettings runtimeSettings = new RuntimeSettings(); Configuration.GetSection("RuntimeSettings").Bind(runtimeSettings); + DirectoryInfo dataProtectionFolder = new DirectoryInfo(Path.Combine(runtimeSettings.DataFolder, "DataProtection")); + + services.AddDataProtection() + .PersistKeysToFileSystem(dataProtectionFolder) + .SetApplicationName("Jackett"); + Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); var builder = new ContainerBuilder();