Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Merge pull request #4672 from NuGet/dev
[ReleasePrep][2017.09.11]RI of dev into master
  • Loading branch information
Scott Bommarito committed Sep 13, 2017
2 parents 9eb4bc4 + 79cae74 commit 1da0dde
Show file tree
Hide file tree
Showing 79 changed files with 3,026 additions and 951 deletions.
1 change: 0 additions & 1 deletion src/Bootstrap/dist/css/bootstrap-theme.css

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 1 addition & 2 deletions src/Bootstrap/less/theme/common-list-packages.less
Expand Up @@ -66,5 +66,4 @@
.pager {
margin-top: 75px;
margin-bottom: 0px;
float: right;
}
}
27 changes: 27 additions & 0 deletions src/NuGetGallery/App_Code/ViewHelpers.cshtml
Expand Up @@ -61,6 +61,33 @@
@Alert(htmlContent, "danger", "ErrorBadge", isAlertRole)
}

@helper AlertIsSemVer2Package(bool hasSemVer2Version, bool hasSemVer2Dependency)
{
string warningHeader = null;
if (hasSemVer2Version)
{
warningHeader = "This package has a SemVer 2.0.0 package version.";
}
else if (hasSemVer2Dependency)
{
warningHeader = "This package is considered a SemVer 2.0.0 package as it has a package dependency on SemVer 2.0.0 package(s).";
}

if (warningHeader != null)
{
@AlertWarning(
@<text>
@warningHeader<br />
<em>
This package will only be available to download with SemVer 2.0.0 compatible NuGet clients, such as Visual
Studio 2017 (version 15.3) and above or NuGet client 4.3.0 and above.
<a href="https://go.microsoft.com/fwlink/?linkid=852248" alt="Read more">Read more</a><br />
</em>
</text>
)
}
}

@helper ErrorPage(UrlHelper url, System.Web.Mvc.HtmlHelper html, string errorNumber, string errorName, Func<MvcHtmlString, HelperResult> errorTextMain, Func<MvcHtmlString, HelperResult> errorTextSub = null)
{
<section role="main" class="container main-container">
Expand Down
7 changes: 7 additions & 0 deletions src/NuGetGallery/App_Start/DefaultDependenciesModule.cs
Expand Up @@ -44,6 +44,8 @@ protected override void Load(ContainerBuilder builder)

var configuration = new ConfigurationService(new SecretReaderFactory(diagnosticsService));

UrlExtensions.SetConfigurationService(configuration);

builder.RegisterInstance(configuration)
.AsSelf()
.As<PoliteCaptcha.IConfigurationSource>();
Expand Down Expand Up @@ -196,6 +198,11 @@ protected override void Load(ContainerBuilder builder)
.As<IReservedNamespaceService>()
.InstancePerLifetimeScope();

builder.RegisterType<PackageUploadService>()
.AsSelf()
.As<IPackageUploadService>()
.InstancePerLifetimeScope();

builder.RegisterType<SecurePushSubscription>()
.SingleInstance();

Expand Down
17 changes: 7 additions & 10 deletions src/NuGetGallery/Configuration/ConfigurationService.cs
Expand Up @@ -122,7 +122,7 @@ public async Task<T> ResolveConfigObject<T>(T instance, string prefix)
}
return instance;
}

public async Task<string> ReadSetting(string settingName)
{
string value;
Expand Down Expand Up @@ -152,7 +152,6 @@ protected virtual HttpRequestBase GetCurrentRequest()
return new HttpRequestWrapper(HttpContext.Current.Request);
}


private ISecretInjector InitSecretInjector()
{
return _secretReaderFactory.CreateSecretInjector(_secretReaderFactory.CreateSecretReader(new ConfigurationService(new EmptySecretReaderFactory())));
Expand Down Expand Up @@ -210,20 +209,18 @@ protected virtual ConnectionStringSettings GetConnectionString(string settingNam
{
return WebConfigurationManager.ConnectionStrings[settingName];
}

private string GetHttpSiteRoot()
{
var request = GetCurrentRequest();
string siteRoot;
var siteRoot = Current.SiteRoot;

if (request.IsLocal)
if (siteRoot == null)
{
// No SiteRoot configured in settings.
// Fallback to detected site root.
var request = GetCurrentRequest();
siteRoot = request.Url.GetLeftPart(UriPartial.Authority) + '/';
}
else
{
siteRoot = Current.SiteRoot;
}

if (!siteRoot.StartsWith("http://", StringComparison.OrdinalIgnoreCase)
&& !siteRoot.StartsWith("https://", StringComparison.OrdinalIgnoreCase))
Expand Down
1 change: 0 additions & 1 deletion src/NuGetGallery/Content/gallery/css/bootstrap-theme.css

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

80 changes: 50 additions & 30 deletions src/NuGetGallery/Controllers/ApiController.cs
Expand Up @@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Globalization;
Expand Down Expand Up @@ -49,6 +50,8 @@ public partial class ApiController
public AuthenticationService AuthenticationService { get; set; }
public ICredentialBuilder CredentialBuilder { get; set; }
protected ISecurityPolicyService SecurityPolicyService { get; set; }
public IReservedNamespaceService ReservedNamespaceService { get; set; }
public IPackageUploadService PackageUploadService { get; set; }

protected ApiController()
{
Expand All @@ -72,7 +75,9 @@ protected ApiController()
ITelemetryService telemetryService,
AuthenticationService authenticationService,
ICredentialBuilder credentialBuilder,
ISecurityPolicyService securityPolicies)
ISecurityPolicyService securityPolicies,
IReservedNamespaceService reservedNamespaceService,
IPackageUploadService packageUploadService)
{
EntitiesContext = entitiesContext;
PackageService = packageService;
Expand All @@ -91,6 +96,8 @@ protected ApiController()
AuthenticationService = authenticationService;
CredentialBuilder = credentialBuilder;
SecurityPolicyService = securityPolicies;
ReservedNamespaceService = reservedNamespaceService;
PackageUploadService = packageUploadService;
StatisticsService = null;
}

Expand All @@ -112,10 +119,13 @@ protected ApiController()
ITelemetryService telemetryService,
AuthenticationService authenticationService,
ICredentialBuilder credentialBuilder,
ISecurityPolicyService securityPolicies)
ISecurityPolicyService securityPolicies,
IReservedNamespaceService reservedNamespaceService,
IPackageUploadService packageUploadService)
: this(entitiesContext, packageService, packageFileService, userService, nugetExeDownloaderService, contentService,
indexingService, searchService, autoCuratePackage, statusService, messageService, auditingService,
configurationService, telemetryService, authenticationService, credentialBuilder, securityPolicies)
configurationService, telemetryService, authenticationService, credentialBuilder, securityPolicies,
reservedNamespaceService, packageUploadService)
{
StatisticsService = statisticsService;
}
Expand Down Expand Up @@ -151,14 +161,14 @@ public virtual async Task<ActionResult> GetPackage(string id, string version)
try
{
var package = PackageService.FindPackageByIdAndVersion(
id,
version,
SemVerLevelKey.SemVer2,
id,
version,
SemVerLevelKey.SemVer2,
allowPrerelease: false);

if (package == null)
{
return new HttpStatusCodeWithBodyResult(HttpStatusCode.NotFound, String.Format(CultureInfo.CurrentCulture, Strings.PackageWithIdAndVersionNotFound, id, version));
return new HttpStatusCodeWithBodyResult(HttpStatusCode.NotFound, String.Format(CultureInfo.CurrentCulture, Strings.PackageWithIdAndVersionNotFound, id, version));
}
version = package.NormalizedVersion;

Expand All @@ -174,7 +184,7 @@ public virtual async Task<ActionResult> GetPackage(string id, string version)
{
QuietLog.LogHandledException(e);

// Database was unavailable and we don't have a version, return a 503
// Database was unavailable and we don't have a version, return a 503
return new HttpStatusCodeWithBodyResult(HttpStatusCode.ServiceUnavailable, Strings.DatabaseUnavailable_TrySpecificVersion);
}
}
Expand Down Expand Up @@ -261,7 +271,7 @@ public async virtual Task<ActionResult> VerifyPackageKeyAsync(string id, string
{
await AuthenticationService.RemoveCredential(user, credential);
}

TelemetryService.TrackVerifyPackageKeyEvent(id, version, user, User.Identity, result?.StatusCode ?? 200);

return (ActionResult)result ?? new EmptyResult();
Expand All @@ -285,7 +295,7 @@ private async Task<HttpStatusCodeWithBodyResult> VerifyPackageKeyInternalAsync(U
{
return new HttpStatusCodeWithBodyResult(HttpStatusCode.Forbidden, Strings.ApiKeyNotAuthorized);
}

if (CredentialTypes.IsPackageVerificationApiKey(credential.Type))
{
// Secure path: verify that verification key matches package scope.
Expand Down Expand Up @@ -370,7 +380,7 @@ private async Task<ActionResult> CreatePackageInternal()
{
message = ex.Message;
}

return new HttpStatusCodeWithBodyResult(HttpStatusCode.BadRequest, message);
}

Expand All @@ -394,17 +404,26 @@ private async Task<ActionResult> CreatePackageInternal()
}

// Ensure that the user can push packages for this partialId.
var packageRegistration = PackageService.FindPackageRegistrationById(nuspec.GetId());
var id = nuspec.GetId();
var packageRegistration = PackageService.FindPackageRegistrationById(id);
IReadOnlyCollection<ReservedNamespace> userOwnedNamespaces = null;
if (packageRegistration == null)
{
// Check if API key allows pushing a new package id
if (!ApiKeyScopeAllows(
subject: nuspec.GetId(),
subject: id,
requestedActions: NuGetScopes.PackagePush))
{
// User cannot push a new package ID as the API key scope does not allow it
return new HttpStatusCodeWithBodyResult(HttpStatusCode.Unauthorized, Strings.ApiKeyNotAuthorized);
}

// For a new package id verify that the user is allowed to push to the matching namespaces, if any.
var isPushAllowed = ReservedNamespaceService.IsPushAllowed(id, user, out userOwnedNamespaces);
if (!isPushAllowed)
{
return new HttpStatusCodeWithBodyResult(HttpStatusCode.Conflict, Strings.UploadPackage_IdNamespaceConflict);
}
}
else
{
Expand All @@ -414,20 +433,20 @@ private async Task<ActionResult> CreatePackageInternal()
// Audit that a non-owner tried to push the package
await AuditingService.SaveAuditRecordAsync(
new FailedAuthenticatedOperationAuditRecord(
user.Username,
AuditedAuthenticatedOperationAction.PackagePushAttemptByNonOwner,
user.Username,
AuditedAuthenticatedOperationAction.PackagePushAttemptByNonOwner,
attemptedPackage: new AuditedPackageIdentifier(
nuspec.GetId(), nuspec.GetVersion().ToNormalizedStringSafe())));
id, nuspec.GetVersion().ToNormalizedStringSafe())));

// User cannot push a package to an ID owned by another user.
return new HttpStatusCodeWithBodyResult(HttpStatusCode.Conflict,
string.Format(CultureInfo.CurrentCulture, Strings.PackageIdNotAvailable,
nuspec.GetId()));
id));
}

// Check if API key allows pushing the current package id
if (!ApiKeyScopeAllows(
packageRegistration.Id,
packageRegistration.Id,
NuGetScopes.PackagePushVersion, NuGetScopes.PackagePush))
{
// User cannot push a package as the API key scope does not allow it
Expand All @@ -448,7 +467,7 @@ private async Task<ActionResult> CreatePackageInternal()
return new HttpStatusCodeWithBodyResult(
HttpStatusCode.Conflict,
string.Format(CultureInfo.CurrentCulture, Strings.PackageExistsAndCannotBeModified,
nuspec.GetId(), nuspec.GetVersion().ToNormalizedStringSafe()));
id, nuspec.GetVersion().ToNormalizedStringSafe()));
}
}

Expand All @@ -459,8 +478,9 @@ private async Task<ActionResult> CreatePackageInternal()
Size = packageStream.Length
};

var package = await PackageService.CreatePackageAsync(
packageToPush,
var package = await PackageUploadService.GeneratePackageAsync(
id,
packageToPush,
packageStreamMetadata,
user,
commitChanges: false);
Expand Down Expand Up @@ -495,16 +515,16 @@ private async Task<ActionResult> CreatePackageInternal()
}

IndexingService.UpdatePackage(package);

// Write an audit record
await AuditingService.SaveAuditRecordAsync(
new PackageAuditRecord(package, AuditedPackageAction.Create, PackageCreatedVia.Api));

// Notify user of push
MessageService.SendPackageAddedNotice(package,
Url.Action("DisplayPackage", "Packages", routeValues: new { id = package.PackageRegistration.Id, version = package.NormalizedVersion }, protocol: Request.Url.Scheme),
Url.Action("ReportMyPackage", "Packages", routeValues: new { id = package.PackageRegistration.Id, version = package.NormalizedVersion }, protocol: Request.Url.Scheme),
Url.Action("Account", "Users", routeValues: null, protocol: Request.Url.Scheme));
Url.Package(package.PackageRegistration.Id, package.NormalizedVersion, Request.Url.Scheme),
Url.ReportPackage(package.PackageRegistration.Id, package.NormalizedVersion, Request.Url.Scheme),
Url.AccountSettings(Request.Url.Scheme));

TelemetryService.TrackPackagePushEvent(package, user, User.Identity);

Expand Down Expand Up @@ -570,7 +590,7 @@ public virtual async Task<ActionResult> DeletePackage(string id, string version)

// Check if API key allows listing/unlisting the current package id
if (!ApiKeyScopeAllows(
subject: id,
subject: id,
requestedActions: NuGetScopes.PackageUnlist))
{
return new HttpStatusCodeWithBodyResult(HttpStatusCode.Forbidden, Strings.ApiKeyNotAuthorized);
Expand Down Expand Up @@ -602,7 +622,7 @@ public virtual async Task<ActionResult> PublishPackage(string id, string version

// Check if API key allows listing/unlisting the current package id
if (!ApiKeyScopeAllows(
subject: id,
subject: id,
requestedActions: NuGetScopes.PackageUnlist))
{
return new HttpStatusCodeWithBodyResult(HttpStatusCode.Forbidden, Strings.ApiKeyNotAuthorized);
Expand Down Expand Up @@ -657,7 +677,7 @@ protected internal virtual Stream ReadPackageFromRequest()
[HttpGet]
[ActionName("PackageIDs")]
public virtual async Task<ActionResult> GetPackageIds(
string partialId,
string partialId,
bool? includePrerelease,
string semVerLevel = null)
{
Expand All @@ -672,7 +692,7 @@ protected internal virtual Stream ReadPackageFromRequest()
[HttpGet]
[ActionName("PackageVersions")]
public virtual async Task<ActionResult> GetPackageVersions(
string id,
string id,
bool? includePrerelease,
string semVerLevel = null)
{
Expand Down Expand Up @@ -701,7 +721,7 @@ public virtual async Task<ActionResult> GetStatsDownloads(int? count)

item.Add("PackageId", row.PackageId);
item.Add("PackageVersion", row.PackageVersion);
item.Add("Gallery", Url.PackageGallery(row.PackageId, row.PackageVersion));
item.Add("Gallery", Url.Package(row.PackageId, row.PackageVersion));
item.Add("PackageTitle", row.PackageTitle ?? row.PackageId);
item.Add("PackageDescription", row.PackageDescription);
item.Add("PackageIconUrl", row.PackageIconUrl ?? Url.PackageDefaultIcon());
Expand Down
8 changes: 6 additions & 2 deletions src/NuGetGallery/Controllers/AppController.cs
Expand Up @@ -54,17 +54,21 @@ protected internal virtual ActionResult SafeRedirect(string returnUrl)
/// <param name="statusCode">HTTP status code for response</param>
/// <param name="obj">Object to Jsonify and return</param>
/// <returns></returns>
protected internal JsonResult Json(int statusCode, object obj)
protected internal JsonResult Json(int statusCode, object obj, JsonRequestBehavior jsonRequestBehavior)
{
Response.StatusCode = statusCode;
if (statusCode >= 400)
{
Response.TrySkipIisCustomErrors = true;
}

return Json(obj);
return Json(obj, jsonRequestBehavior);
}

protected internal JsonResult Json(int statusCode, object obj)
{
return Json(statusCode, obj, JsonRequestBehavior.DenyGet);
}

/// <summary>
/// Called before the action method is invoked.
Expand Down

0 comments on commit 1da0dde

Please sign in to comment.