private string GetHttpsSiteRoot()
        {
            var siteRoot = UrlExtensions.MakeSecure(_httpSiteRootThunk.Value);

            if (siteRoot.StartsWith("http://", StringComparison.OrdinalIgnoreCase) || siteRoot.StartsWith("https://", StringComparison.OrdinalIgnoreCase))
            {
                return(siteRoot);
            }

            throw new InvalidOperationException("The configured HTTP site root must start with http:// or https://.");
        }
        protected static Uri BuildLinkForStreamProperty(string routePrefix, string id, string version, HttpRequestMessage request)
        {
            var url    = new UrlHelper(request);
            var result = url.Route(routePrefix + RouteName.DownloadPackage, new { id, version });

            var builder = new UriBuilder(UrlExtensions.MakeSecure(request.RequestUri));

            builder.Path = version == null?EnsureTrailingSlash(result) : result;

            builder.Query = string.Empty;

            return(builder.Uri);
        }
        private string GetHttpSiteRoot()
        {
            var siteRoot = Current.SiteRoot;

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

            if (!siteRoot.StartsWith("http://", StringComparison.OrdinalIgnoreCase) &&
                !siteRoot.StartsWith("https://", StringComparison.OrdinalIgnoreCase))
            {
                throw new InvalidOperationException("The configured site root must start with either http:// or https://.");
            }

            return(UrlExtensions.MakeSecure(siteRoot));
        }
Пример #4
0
        public static async Task <SearchAdaptorResult> FindByIdAndVersionCore(
            ISearchService searchService,
            HttpRequestBase request,
            IQueryable <Package> packages,
            string id,
            string version,
            CuratedFeed curatedFeed,
            string semVerLevel)
        {
            SearchFilter searchFilter;

            // We can only use Lucene if:
            //  a) The Index contains all versions of each package
            //  b) The sort order is something Lucene can handle
            if (TryReadSearchFilter(searchService.ContainsAllVersions, UrlExtensions.MakeSecure(request.RawUrl), searchService.ContainsAllVersions, out searchFilter) && !string.IsNullOrWhiteSpace(id))
            {
                var normalizedRegistrationId = id.Normalize(NormalizationForm.FormC);

                var searchTerm = string.Format(CultureInfo.CurrentCulture, "Id:\"{0}\"", normalizedRegistrationId);
                if (!string.IsNullOrEmpty(version))
                {
                    searchTerm = string.Format(CultureInfo.CurrentCulture, "Id:\"{0}\" AND Version:\"{1}\"", normalizedRegistrationId, version);

                    searchFilter.Take = 1; // only one result is needed in this case
                }

                searchFilter.SearchTerm         = searchTerm;
                searchFilter.SemVerLevel        = semVerLevel;
                searchFilter.IncludePrerelease  = true;
                searchFilter.CuratedFeed        = curatedFeed;
                searchFilter.SupportedFramework = null;
                searchFilter.IncludeAllVersions = true;

                var results = await GetRawResultsFromSearchService(searchService, searchFilter);

                return(new SearchAdaptorResult(true, results));
            }

            return(new SearchAdaptorResult(false, packages));
        }
Пример #5
0
        public static async Task <SearchAdaptorResult> SearchCore(
            ISearchService searchService,
            HttpRequestBase request,
            IQueryable <Package> packages,
            string searchTerm,
            string targetFramework,
            bool includePrerelease,
            CuratedFeed curatedFeed,
            string semVerLevel)
        {
            SearchFilter searchFilter;

            // We can only use Lucene if:
            //  a) We are looking for the latest version of a package OR the Index contains all versions of each package
            //  b) The sort order is something Lucene can handle
            if (TryReadSearchFilter(searchService.ContainsAllVersions, UrlExtensions.MakeSecure(request.RawUrl), false, out searchFilter))
            {
                searchFilter.SearchTerm         = searchTerm;
                searchFilter.IncludePrerelease  = includePrerelease;
                searchFilter.CuratedFeed        = curatedFeed;
                searchFilter.SupportedFramework = targetFramework;
                searchFilter.SemVerLevel        = semVerLevel;

                var results = await GetResultsFromSearchService(searchService, searchFilter);

                return(new SearchAdaptorResult(true, results));
            }

            if (!includePrerelease)
            {
                packages = packages.Where(p => !p.IsPrerelease);
            }

            packages = packages.Where(SemVerLevelKey.IsPackageCompliantWithSemVerLevelPredicate(semVerLevel));

            return(new SearchAdaptorResult(false, packages.Search(searchTerm)));
        }
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            if (filterContext == null)
            {
                throw new ArgumentNullException(nameof(filterContext));
            }

            if (!filterContext.HttpContext.Request.IsAuthenticated)
            {
                throw new InvalidOperationException("Requires account confirmation attribute is only valid on authenticated actions.");
            }
            
            var controller = ((AppController)filterContext.Controller);
            var user = controller.GetCurrentUser();
            
            if (!user.Confirmed)
            {
                controller.TempData["ConfirmationRequiredMessage"] = string.Format(
                    CultureInfo.CurrentCulture,
                    "Before you can {0} you must first confirm your email address.", _inOrderTo);
                controller.HttpContext.SetConfirmationReturnUrl(UrlExtensions.MakeSecure(controller.Url.RequestContext.HttpContext.Request.RawUrl));
                filterContext.Result = new RedirectResult(controller.Url.ConfirmationRequired(relativeUrl: false));
            }
        }
Пример #7
0
        public async Task <IHttpActionResult> Search(
            ODataQueryOptions <V2FeedPackage> options,
            string curatedFeedName,
            [FromODataUri] string searchTerm      = "",
            [FromODataUri] string targetFramework = "",
            [FromODataUri] bool includePrerelease = false,
            [FromUri] string semVerLevel          = null)
        {
            if (!_entities.CuratedFeeds.Any(cf => cf.Name == curatedFeedName))
            {
                return(NotFound());
            }

            // Handle OData-style |-separated list of frameworks.
            string[] targetFrameworkList = (targetFramework ?? "").Split(new[] { '\'', '|' }, StringSplitOptions.RemoveEmptyEntries);

            // For now, we'll just filter on the first one.
            if (targetFrameworkList.Length > 0)
            {
                // Until we support multiple frameworks, we need to prefer aspnet50 over aspnetcore50.
                if (targetFrameworkList.Contains("aspnet50"))
                {
                    targetFramework = "aspnet50";
                }
                else
                {
                    targetFramework = targetFrameworkList[0];
                }
            }

            // Perform actual search
            var curatedFeed = _curatedFeedService.GetFeedByName(curatedFeedName, includePackages: false);
            var packages    = _curatedFeedService.GetPackages(curatedFeedName)
                              .Where(p => p.PackageStatusKey == PackageStatus.Available)
                              .Where(SemVerLevelKey.IsPackageCompliantWithSemVerLevelPredicate(semVerLevel))
                              .OrderBy(p => p.PackageRegistration.Id).ThenBy(p => p.Version);

            // todo: search hijack should take queryOptions instead of manually parsing query options
            var searchAdaptorResult = await SearchAdaptor.SearchCore(
                _searchService,
                GetTraditionalHttpContext().Request,
                packages,
                searchTerm,
                targetFramework,
                includePrerelease,
                curatedFeed : curatedFeed,
                semVerLevel : semVerLevel);

            // Packages provided by search service (even when not hijacked)
            var query = searchAdaptorResult.Packages;

            var semVerLevelKey = SemVerLevelKey.ForSemVerLevel(semVerLevel);

            // If intercepted, create a paged queryresult
            if (searchAdaptorResult.ResultsAreProvidedBySearchService)
            {
                // Add explicit Take() needed to limit search hijack result set size if $top is specified
                var totalHits      = query.LongCount();
                var pagedQueryable = query
                                     .Take(options.Top != null ? Math.Min(options.Top.Value, MaxPageSize) : MaxPageSize)
                                     .ToV2FeedPackageQuery(
                    GetSiteRoot(),
                    _configurationService.Features.FriendlyLicenses,
                    semVerLevelKey);

                return(QueryResult(options, pagedQueryable, MaxPageSize, totalHits, (o, s, resultCount) =>
                {
                    // The nuget.exe 2.x list command does not like the next link at the bottom when a $top is passed.
                    // Strip it of for backward compatibility.
                    if (o.Top == null || (resultCount.HasValue && o.Top.Value >= resultCount.Value))
                    {
                        return SearchAdaptor.GetNextLink(
                            UrlExtensions.MakeSecure(Request.RequestUri),
                            resultCount,
                            new { searchTerm, targetFramework, includePrerelease },
                            o,
                            s);
                    }
                    return null;
                }));
            }

            // If not, just let OData handle things
            var queryable = query.ToV2FeedPackageQuery(
                GetSiteRoot(),
                _configurationService.Features.FriendlyLicenses,
                semVerLevelKey);

            return(QueryResult(options, queryable, MaxPageSize));
        }
Пример #8
0
        private async Task <IHttpActionResult> GetCore(
            ODataQueryOptions <V2FeedPackage> options,
            string curatedFeedName,
            string id,
            string normalizedVersion,
            bool return404NotFoundWhenNoResults,
            string semVerLevel)
        {
            var curatedFeed = _entities.CuratedFeeds.FirstOrDefault(cf => cf.Name == curatedFeedName);

            if (curatedFeed == null)
            {
                return(NotFound());
            }

            var packages = _curatedFeedService
                           .GetPackages(curatedFeedName)
                           .Where(p => p.PackageStatusKey == PackageStatus.Available)
                           .Where(SemVerLevelKey.IsPackageCompliantWithSemVerLevelPredicate(semVerLevel))
                           .Where(p => p.PackageRegistration.Id.Equals(id, StringComparison.OrdinalIgnoreCase));

            if (!string.IsNullOrEmpty(normalizedVersion))
            {
                packages = packages.Where(p => p.NormalizedVersion == normalizedVersion);
            }

            var semVerLevelKey = SemVerLevelKey.ForSemVerLevel(semVerLevel);

            // try the search service
            try
            {
                var searchAdaptorResult = await SearchAdaptor.FindByIdAndVersionCore(
                    _searchService,
                    GetTraditionalHttpContext().Request,
                    packages,
                    id,
                    normalizedVersion,
                    curatedFeed : curatedFeed,
                    semVerLevel : semVerLevel);

                // If intercepted, create a paged queryresult
                if (searchAdaptorResult.ResultsAreProvidedBySearchService)
                {
                    // Packages provided by search service
                    packages = searchAdaptorResult.Packages;

                    // Add explicit Take() needed to limit search hijack result set size if $top is specified
                    var totalHits = packages.LongCount();

                    if (return404NotFoundWhenNoResults && totalHits == 0)
                    {
                        return(NotFound());
                    }

                    var pagedQueryable = packages
                                         .Take(options.Top != null ? Math.Min(options.Top.Value, MaxPageSize) : MaxPageSize)
                                         .ToV2FeedPackageQuery(UrlExtensions.MakeSecure(GetSiteRoot()), _configurationService.Features.FriendlyLicenses, semVerLevelKey);

                    return(QueryResult(options, pagedQueryable, MaxPageSize, totalHits, (o, s, resultCount) =>
                                       SearchAdaptor.GetNextLink(UrlExtensions.MakeSecure(Request.RequestUri), resultCount, new { id }, o, s)));
                }
            }
            catch (Exception ex)
            {
                // Swallowing Exception intentionally. If *anything* goes wrong in search, just fall back to the database.
                // We don't want to break package restores. We do want to know if this happens, so here goes:
                QuietLog.LogHandledException(ex);
            }

            if (return404NotFoundWhenNoResults && !packages.Any())
            {
                return(NotFound());
            }

            var queryable = packages.ToV2FeedPackageQuery(
                UrlExtensions.MakeSecure(GetSiteRoot()),
                _configurationService.Features.FriendlyLicenses,
                semVerLevelKey);

            return(QueryResult(options, queryable, MaxPageSize));
        }
Пример #9
0
        public async Task <IHttpActionResult> Get(
            ODataQueryOptions <V2FeedPackage> options,
            [FromUri] string semVerLevel = null)
        {
            // Setup the search
            var packages = _packagesRepository.GetAll()
                           .Where(p => p.PackageStatusKey == PackageStatus.Available)
                           .Where(SemVerLevelKey.IsPackageCompliantWithSemVerLevelPredicate(semVerLevel))
                           .WithoutSortOnColumn(Version)
                           .WithoutSortOnColumn(Id, ShouldIgnoreOrderById(options))
                           .InterceptWith(new NormalizeVersionInterceptor());

            var semVerLevelKey = SemVerLevelKey.ForSemVerLevel(semVerLevel);

            // Try the search service
            try
            {
                HijackableQueryParameters hijackableQueryParameters = null;
                if (_searchService is ExternalSearchService && SearchHijacker.IsHijackable(options, out hijackableQueryParameters))
                {
                    var searchAdaptorResult = await SearchAdaptor.FindByIdAndVersionCore(
                        _searchService,
                        GetTraditionalHttpContext().Request,
                        packages,
                        hijackableQueryParameters.Id,
                        hijackableQueryParameters.Version,
                        curatedFeed : null,
                        semVerLevel : semVerLevel);

                    // If intercepted, create a paged queryresult
                    if (searchAdaptorResult.ResultsAreProvidedBySearchService)
                    {
                        // Packages provided by search service
                        packages = searchAdaptorResult.Packages;

                        // Add explicit Take() needed to limit search hijack result set size if $top is specified
                        var totalHits      = packages.LongCount();
                        var pagedQueryable = packages
                                             .Take(options.Top != null ? Math.Min(options.Top.Value, MaxPageSize) : MaxPageSize)
                                             .ToV2FeedPackageQuery(
                            GetSiteRoot(),
                            _configurationService.Features.FriendlyLicenses,
                            semVerLevelKey);

                        return(QueryResult(options, pagedQueryable, MaxPageSize, totalHits, (o, s, resultCount) =>
                                           SearchAdaptor.GetNextLink(UrlExtensions.MakeSecure(Request.RequestUri), resultCount, null, o, s)));
                    }
                }
            }
            catch (Exception ex)
            {
                // Swallowing Exception intentionally. If *anything* goes wrong in search, just fall back to the database.
                // We don't want to break package restores. We do want to know if this happens, so here goes:
                QuietLog.LogHandledException(ex);
            }

            // Reject only when try to reach database.
            if (!ODataQueryVerifier.AreODataOptionsAllowed(options, ODataQueryVerifier.V2Packages,
                                                           _configurationService.Current.IsODataFilterEnabled, nameof(Get)))
            {
                return(BadRequest(ODataQueryVerifier.GetValidationFailedMessage(options)));
            }

            var queryable = packages.ToV2FeedPackageQuery(
                GetSiteRoot(),
                _configurationService.Features.FriendlyLicenses,
                semVerLevelKey);

            return(QueryResult(options, queryable, MaxPageSize));
        }
Пример #10
0
        private async Task <IHttpActionResult> GetCore(ODataQueryOptions <V1FeedPackage> options, string id, string version, bool return404NotFoundWhenNoResults)
        {
            var packages = _packagesRepository.GetAll()
                           .Include(p => p.PackageRegistration)
                           .Where(p => p.PackageRegistration.Id.Equals(id, StringComparison.OrdinalIgnoreCase) &&
                                  !p.IsPrerelease &&
                                  p.PackageStatusKey == PackageStatus.Available)
                           .Where(SemVerLevelKey.IsUnknownPredicate());

            if (!string.IsNullOrEmpty(version))
            {
                packages = packages.Where(p => p.Version == version);
            }

            // try the search service
            try
            {
                var searchAdaptorResult = await SearchAdaptor.FindByIdAndVersionCore(
                    _searchService,
                    GetTraditionalHttpContext().Request,
                    packages,
                    id,
                    version,
                    curatedFeed : null,
                    semVerLevel : null);

                // If intercepted, create a paged queryresult
                if (searchAdaptorResult.ResultsAreProvidedBySearchService)
                {
                    // Packages provided by search service
                    packages = searchAdaptorResult.Packages;

                    // Add explicit Take() needed to limit search hijack result set size if $top is specified
                    var totalHits = packages.LongCount();

                    if (return404NotFoundWhenNoResults && totalHits == 0)
                    {
                        return(NotFound());
                    }

                    var pagedQueryable = packages
                                         .Take(options.Top != null ? Math.Min(options.Top.Value, MaxPageSize) : MaxPageSize)
                                         .ToV1FeedPackageQuery(GetSiteRoot());

                    return(QueryResult(options, pagedQueryable, MaxPageSize, totalHits, (o, s, resultCount) =>
                                       SearchAdaptor.GetNextLink(UrlExtensions.MakeSecure(Request.RequestUri), resultCount, new { id }, o, s)));
                }
            }
            catch (Exception ex)
            {
                // Swallowing Exception intentionally. If *anything* goes wrong in search, just fall back to the database.
                // We don't want to break package restores. We do want to know if this happens, so here goes:
                QuietLog.LogHandledException(ex);
            }

            if (return404NotFoundWhenNoResults && !packages.Any())
            {
                return(NotFound());
            }

            var queryable = packages.ToV1FeedPackageQuery(GetSiteRoot());

            return(QueryResult(options, queryable, MaxPageSize));
        }
Пример #11
0
        public async Task <IHttpActionResult> Search(
            ODataQueryOptions <V1FeedPackage> options,
            [FromODataUri] string searchTerm      = "",
            [FromODataUri] string targetFramework = "")
        {
            // Handle OData-style |-separated list of frameworks.
            string[] targetFrameworkList = (targetFramework ?? "").Split(new[] { '\'', '|' }, StringSplitOptions.RemoveEmptyEntries);

            // For now, we'll just filter on the first one.
            if (targetFrameworkList.Length > 0)
            {
                // Until we support multiple frameworks, we need to prefer aspnet50 over aspnetcore50.
                if (targetFrameworkList.Contains("aspnet50"))
                {
                    targetFramework = "aspnet50";
                }
                else
                {
                    targetFramework = targetFrameworkList[0];
                }
            }

            // Perform actual search
            var packages = _packagesRepository.GetAll()
                           .Include(p => p.PackageRegistration)
                           .Include(p => p.PackageRegistration.Owners)
                           .Where(p => p.Listed && !p.IsPrerelease && p.PackageStatusKey == PackageStatus.Available)
                           .Where(SemVerLevelKey.IsUnknownPredicate())
                           .OrderBy(p => p.PackageRegistration.Id).ThenBy(p => p.Version)
                           .AsNoTracking();

            // todo: search hijack should take queryOptions instead of manually parsing query options
            var searchAdaptorResult = await SearchAdaptor.SearchCore(
                _searchService,
                GetTraditionalHttpContext().Request,
                packages,
                searchTerm,
                targetFramework,
                false,
                curatedFeed : null,
                semVerLevel : null);

            // Packages provided by search service (even when not hijacked)
            var query = searchAdaptorResult.Packages;

            // If intercepted, create a paged queryresult
            if (searchAdaptorResult.ResultsAreProvidedBySearchService)
            {
                // Add explicit Take() needed to limit search hijack result set size if $top is specified
                var totalHits      = query.LongCount();
                var pagedQueryable = query
                                     .Take(options.Top != null ? Math.Min(options.Top.Value, MaxPageSize) : MaxPageSize)
                                     .ToV1FeedPackageQuery(GetSiteRoot());

                return(QueryResult(options, pagedQueryable, MaxPageSize, totalHits, (o, s, resultCount) =>
                                   SearchAdaptor.GetNextLink(UrlExtensions.MakeSecure(Request.RequestUri), resultCount, new { searchTerm, targetFramework }, o, s)));
            }

            if (!ODataQueryVerifier.AreODataOptionsAllowed(options, ODataQueryVerifier.V1Search,
                                                           _configurationService.Current.IsODataFilterEnabled, nameof(Search)))
            {
                return(BadRequest(ODataQueryVerifier.GetValidationFailedMessage(options)));
            }

            // If not, just let OData handle things
            var queryable = query.ToV1FeedPackageQuery(GetSiteRoot());

            return(QueryResult(options, queryable, MaxPageSize));
        }