Skip to content

Commit a3e9ede

Browse files
authored
Image allowlist (#8406)
* image allowlist display image on upload, display, manage page * store allowlist to content folder & add new imageValidator service
1 parent 49e9350 commit a3e9ede

30 files changed

Lines changed: 416 additions & 45 deletions

src/NuGetGallery.Services/Configuration/FeatureFlagService.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ public class FeatureFlagService : IFeatureFlagService
4444
private const string LicenseMdRenderingFlightName = GalleryPrefix + "LicenseMdRendering";
4545
private const string MarkdigMdRenderingFlightName = GalleryPrefix + "MarkdigMdRendering";
4646
private const string DeletePackageApiFlightName = GalleryPrefix + "DeletePackageApi";
47+
private const string ImageAllowlistFlightName = GalleryPrefix + "ImageAllowlist";
4748

4849
private const string ODataV1GetAllNonHijackedFeatureName = GalleryPrefix + "ODataV1GetAllNonHijacked";
4950
private const string ODataV1GetAllCountNonHijackedFeatureName = GalleryPrefix + "ODataV1GetAllCountNonHijacked";
@@ -308,5 +309,10 @@ public bool IsDeletePackageApiEnabled(User user)
308309
{
309310
return _client.IsEnabled(DeletePackageApiFlightName, user, defaultValue: false);
310311
}
312+
313+
public bool IsImageAllowlistEnabled()
314+
{
315+
return _client.IsEnabled(ImageAllowlistFlightName, defaultValue: false);
316+
}
311317
}
312318
}

src/NuGetGallery.Services/Configuration/IFeatureFlagService.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,5 +245,10 @@ public interface IFeatureFlagService
245245
/// Whether or not the user can delete a package through the API.
246246
/// </summary>
247247
bool IsDeletePackageApiEnabled(User user);
248+
249+
/// <summary>
250+
/// Whether the allowlist is enabled for checking the image sources
251+
/// </summary>
252+
bool IsImageAllowlistEnabled();
248253
}
249254
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
namespace NuGetGallery.Services
5+
{
6+
public interface ITrustedImageDomains
7+
{
8+
/// <summary>
9+
/// Return true if input imageDomain is in trusted image allowlist, Otherwise, return false
10+
/// </summary>
11+
bool IsImageDomainTrusted(string imageDomain);
12+
}
13+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System;
5+
using System.Collections.Generic;
6+
using System.Linq;
7+
using System.Text;
8+
using System.Threading.Tasks;
9+
using Newtonsoft.Json;
10+
11+
namespace NuGetGallery.Services
12+
{
13+
public class TrustedImageDomains : ITrustedImageDomains
14+
{
15+
public HashSet<string> TrustedImageDomainList { get; }
16+
17+
public TrustedImageDomains()
18+
: this(trustedImageDomainList: Enumerable.Empty<string>())
19+
{
20+
21+
}
22+
23+
[JsonConstructor]
24+
public TrustedImageDomains(IEnumerable<string> trustedImageDomainList)
25+
{
26+
if (trustedImageDomainList == null)
27+
{
28+
throw new ArgumentNullException(nameof(trustedImageDomainList));
29+
}
30+
31+
TrustedImageDomainList = new HashSet<string>(trustedImageDomainList, StringComparer.OrdinalIgnoreCase);
32+
}
33+
34+
public bool IsImageDomainTrusted(string imageDomain)
35+
{
36+
if (imageDomain == null)
37+
{
38+
return false;
39+
}
40+
41+
return TrustedImageDomainList.Contains(imageDomain);
42+
}
43+
}
44+
}

src/NuGetGallery.Services/NuGetGallery.Services.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@
120120
<Compile Include="Configuration\IQueryHintConfiguration.cs" />
121121
<Compile Include="Configuration\IServiceBusConfiguration.cs" />
122122
<Compile Include="Configuration\ISymbolsConfiguration.cs" />
123+
<Compile Include="Configuration\ITrustedImageDomains.cs" />
123124
<Compile Include="Configuration\ITyposquattingConfiguration.cs" />
124125
<Compile Include="Configuration\LoginDiscontinuationConfiguration.cs" />
125126
<Compile Include="Configuration\ODataCacheConfiguration.cs" />
@@ -130,6 +131,7 @@
130131
<Compile Include="Configuration\ServiceBusConfiguration.cs" />
131132
<Compile Include="Configuration\SimpleBlobStorageConfiguration.cs" />
132133
<Compile Include="Configuration\SymbolsConfiguration.cs" />
134+
<Compile Include="Configuration\TrustedImageDomains.cs" />
133135
<Compile Include="Configuration\TyposquattingConfiguration.cs" />
134136
<Compile Include="Diagnostics\DiagnosticsService.cs" />
135137
<Compile Include="Diagnostics\ElmahHandleErrorAttribute.cs" />

src/NuGetGallery.Services/ServicesConstants.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ public static class ContentNames
6262
public static readonly string ODataCacheConfiguration = "OData-Cache-Configuration";
6363
public static readonly string CacheConfiguration = "Cache-Configuration";
6464
public static readonly string QueryHintConfiguration = "Query-Hint-Configuration";
65+
public static readonly string TrustedImageDomains = "Trusted-Image-Domains";
6566
}
6667
}
6768
}

src/NuGetGallery.Services/Storage/ContentObjectService.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ public ContentObjectService(IContentService contentService)
2828
ODataCacheConfiguration = new ODataCacheConfiguration();
2929
CacheConfiguration = new CacheConfiguration();
3030
QueryHintConfiguration = new QueryHintConfiguration();
31+
TrustedImageDomains = new TrustedImageDomains();
3132
}
3233

3334
public ILoginDiscontinuationConfiguration LoginDiscontinuationConfiguration { get; private set; }
@@ -39,6 +40,7 @@ public ContentObjectService(IContentService contentService)
3940
public IODataCacheConfiguration ODataCacheConfiguration { get; private set; }
4041
public ICacheConfiguration CacheConfiguration { get; private set; }
4142
public IQueryHintConfiguration QueryHintConfiguration { get; private set; }
43+
public ITrustedImageDomains TrustedImageDomains { get; private set; }
4244

4345
public async Task Refresh()
4446
{
@@ -78,6 +80,10 @@ await Refresh<CacheConfiguration>(ServicesConstants.ContentNames.CacheConfigurat
7880
QueryHintConfiguration =
7981
await Refresh<QueryHintConfiguration>(ServicesConstants.ContentNames.QueryHintConfiguration) ??
8082
new QueryHintConfiguration();
83+
84+
TrustedImageDomains =
85+
await Refresh<TrustedImageDomains>(ServicesConstants.ContentNames.TrustedImageDomains) ??
86+
new TrustedImageDomains();
8187
}
8288

8389
private async Task<T> Refresh<T>(string contentName)

src/NuGetGallery.Services/Storage/IContentObjectService.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ public interface IContentObjectService
1717
IODataCacheConfiguration ODataCacheConfiguration { get; }
1818
ICacheConfiguration CacheConfiguration { get; }
1919
IQueryHintConfiguration QueryHintConfiguration { get; }
20+
ITrustedImageDomains TrustedImageDomains { get; }
2021

2122
Task Refresh();
2223
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
{
2+
"TrustedImageDomainList": [
3+
"api.bintray.com",
4+
"api.codacy.com",
5+
"api.codeclimate.com",
6+
"api.dependabot.com",
7+
"api.travis-ci.com",
8+
"api.travis-ci.org",
9+
"app.fossa.io",
10+
"badge.fury.io",
11+
"badgen.net",
12+
"badges.gitter.im",
13+
"bettercodehub.com",
14+
"buildstats.info",
15+
"ci.appveyor.com",
16+
"circleci.com",
17+
"codecov.io",
18+
"codefactor.io",
19+
"coveralls.io",
20+
"dev.azure.com",
21+
"gitlab.com",
22+
"img.shields.io",
23+
"isitmaintained.com",
24+
"opencollective.com",
25+
"snyk.io",
26+
"sonarcloud.io",
27+
"raw.github.com",
28+
"raw.githubusercontent.com",
29+
"user-images.githubusercontent.com",
30+
"camo.githubusercontent.com"
31+
]
32+
}

src/NuGetGallery/App_Start/DefaultDependenciesModule.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,10 @@ protected override void Load(ContainerBuilder builder)
374374
builder.RegisterType<MarkdownService>()
375375
.As<IMarkdownService>()
376376
.InstancePerLifetimeScope();
377+
378+
builder.RegisterType<ImageDomainValidator>()
379+
.As<IImageDomainValidator>()
380+
.InstancePerLifetimeScope();
377381

378382
builder.RegisterType<ApiScopeEvaluator>()
379383
.AsSelf()

0 commit comments

Comments
 (0)