diff --git a/.nuget/packages.config b/.nuget/packages.config index b3d73c344..9e830ed15 100644 --- a/.nuget/packages.config +++ b/.nuget/packages.config @@ -1,6 +1,6 @@  - + \ No newline at end of file diff --git a/src/NuGet.Indexing/AzureDirectorySynchronizer.cs b/src/NuGet.Indexing/AzureDirectorySynchronizer.cs index 8f57764ef..ab4d08dfa 100644 --- a/src/NuGet.Indexing/AzureDirectorySynchronizer.cs +++ b/src/NuGet.Indexing/AzureDirectorySynchronizer.cs @@ -104,7 +104,7 @@ private static void UnidirectionalSync(AzureDirectory sourceDirectory, Directory // we'll remove old files from both AzureDirectory's cache directory, as well as our destination directory // (only when older than 45 minutes - old files may still have active searches on them so we need a margin) - var referenceTimestamp = LuceneTimestampFromDateTime(DateTimeOffset.UtcNow.AddMinutes(-45)); + var referenceTimestamp = LuceneTimestampFromDateTime(DateTime.UtcNow.AddMinutes(-45)); // remove old files from AzureDirectory cache directory RemoveOldFiles(sourceDirectory.CacheDirectory, sourceFiles, referenceTimestamp); @@ -126,11 +126,10 @@ private static void RemoveOldFiles(Directory directory, string[] skipFiles, long } } - private static long LuceneTimestampFromDateTime(DateTimeOffset date) + private static long LuceneTimestampFromDateTime(DateTime date) { - var epoch = new DateTimeOffset(1970, 1, 1, 0, 0, 0, TimeSpan.Zero); - - return (date.UtcTicks - epoch.UtcTicks) / TimeSpan.TicksPerSecond * 1000; + // Use ToFileTimeUtc here to stay consistent with the returns from AzureDirectory. + return date.ToFileTimeUtc(); } } } diff --git a/src/NuGet.Indexing/NuGet.Indexing.csproj b/src/NuGet.Indexing/NuGet.Indexing.csproj index a47a4a945..56010c62b 100644 --- a/src/NuGet.Indexing/NuGet.Indexing.csproj +++ b/src/NuGet.Indexing/NuGet.Indexing.csproj @@ -234,6 +234,7 @@ + diff --git a/src/NuGet.Indexing/NuGetSearcherManager.cs b/src/NuGet.Indexing/NuGetSearcherManager.cs index f9eca906c..4d0642ee6 100644 --- a/src/NuGet.Indexing/NuGetSearcherManager.cs +++ b/src/NuGet.Indexing/NuGetSearcherManager.cs @@ -121,7 +121,7 @@ public class NuGetSearcherManager : SearcherManager if (directory == null) { var sourceDirectory = new AzureDirectory(storageAccount, indexContainer); - directory = new RAMDirectory(sourceDirectory); // initial copy from storage to RAM + directory = new RAMDirectoryWrapper(sourceDirectory); // initial copy from storage to RAM azureDirectorySynchronizer = new AzureDirectorySynchronizer(sourceDirectory, directory); } diff --git a/src/NuGet.Indexing/RAMDirectoryWrapper.cs b/src/NuGet.Indexing/RAMDirectoryWrapper.cs new file mode 100644 index 000000000..6a10ebe5d --- /dev/null +++ b/src/NuGet.Indexing/RAMDirectoryWrapper.cs @@ -0,0 +1,36 @@ +using Lucene.Net.Store; +using System; + +namespace NuGet.Indexing +{ + /// + /// This class wraps the RAMDirectory so we can correct the return of FileModified function + /// + public class RAMDirectoryWrapper: RAMDirectory + { + public RAMDirectoryWrapper() : base() { } + + public RAMDirectoryWrapper(Directory seedDirectory) : base(seedDirectory) { } + + /// + /// Returns the time (as a long) the named file was last modified in a Windows FileTime in UTC + /// + /// File Name + /// A long that represents a UTC Windows FileTime + /// The implementation here is to keep in line with the implementation in AzureDirectory for use in the . + /// See https://github.com/azure-contrib/AzureDirectory/blob/master/AzureDirectory/AzureDirectory.cs#L147 for AzureDirectory implementation + public override long FileModified(string name) + { + // The RAMDirectory implementation of FileModified creates a dateTime, converts to localTime, and then uses ticks to get milliseconds. + // Undo this conversion here so we can get the file modified time in ticks back (accurate to the millisecond, we lose some precision here) + // Then operate on this to get back a "standard" utc windows filetime. + // See https://lucenenet.apache.org/docs/3.0.3/d7/df5/_r_a_m_directory_8cs_source.html line 114 for more details. + + var originalTicks = base.FileModified(name) * TimeSpan.TicksPerMillisecond; + + var newTime = new DateTime(originalTicks, DateTimeKind.Local); + + return newTime.ToUniversalTime().ToFileTimeUtc(); + } + } +} diff --git a/src/NuGet.Services.BasicSearch/Startup.cs b/src/NuGet.Services.BasicSearch/Startup.cs index ad99d1f84..8e15bf2bc 100644 --- a/src/NuGet.Services.BasicSearch/Startup.cs +++ b/src/NuGet.Services.BasicSearch/Startup.cs @@ -71,6 +71,13 @@ public void Configuration(IAppBuilder app, IConfiguration configuration, Directo // Add Application Insights app.Use(typeof(RequestTrackingMiddleware)); + // Enable HSTS + app.Use(async (context, next) => + { + context.Response.Headers.Add("Strict-Transport-Security", new string[] { "max-age=31536000; includeSubDomains" }); + await next.Invoke(); + }); + // Enable CORS var corsPolicy = new CorsPolicy { diff --git a/tests/NuGet.Services.BasicSearchTests/TestSupport/LuceneDirectoryInitializer.cs b/tests/NuGet.Services.BasicSearchTests/TestSupport/LuceneDirectoryInitializer.cs index 8819253f1..33381c5c3 100644 --- a/tests/NuGet.Services.BasicSearchTests/TestSupport/LuceneDirectoryInitializer.cs +++ b/tests/NuGet.Services.BasicSearchTests/TestSupport/LuceneDirectoryInitializer.cs @@ -59,7 +59,7 @@ private Lucene.Net.Store.Directory CreateLuceneIndex(IEnumerable } else { - directory = new RAMDirectory(); + directory = new RAMDirectoryWrapper(); } using (var indexWriter = DocumentCreator.CreateIndexWriter(directory, true))