diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4868026ed..23e0125ce 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,10 @@
# Snyk Security Changelog
+## [1.1.59]
+
+### Fixed
+- Change Default API Endpoint to https://api.snyk.io.
+
## [1.1.58]
### Fixed
diff --git a/Snyk.Common/Service/ApiEndpointResolver.cs b/Snyk.Common/Service/ApiEndpointResolver.cs
index 0893ae6f6..e0ab644d9 100644
--- a/Snyk.Common/Service/ApiEndpointResolver.cs
+++ b/Snyk.Common/Service/ApiEndpointResolver.cs
@@ -1,15 +1,18 @@
-namespace Snyk.Common.Service
-{
- using System;
- using Snyk.Common.Authentication;
- using Snyk.Common.Settings;
+using System;
+using System.Text.RegularExpressions;
+using Snyk.Common.Authentication;
+using Snyk.Common.Settings;
+namespace Snyk.Common.Service
+{
///
/// Helper class for resolve API endpoints. It's one place for all endpoint calculations.
///
public class ApiEndpointResolver
{
private readonly ISnykOptions options;
+ private const string DefaultApiEndpoint = "https://api.snyk.io";
+ public const string DefaultAppEndpoint = "https://app.snyk.io";
///
/// Initializes a new instance of the class.
@@ -53,7 +56,7 @@ public string GetSnykApiEndpoint()
{
var customEndpoint = ResolveCustomEndpoint(this.options.CustomEndpoint);
- var sastUrl = string.IsNullOrEmpty(customEndpoint) ? "https://snyk.io/api/" : customEndpoint;
+ var sastUrl = string.IsNullOrEmpty(customEndpoint) ? DefaultApiEndpoint : customEndpoint;
return !sastUrl.EndsWith("/") ? $"{sastUrl}/" : sastUrl;
}
@@ -63,54 +66,45 @@ public string GetSnykApiEndpoint()
///
public string GetSnykCodeApiUrl()
{
- if (this.IsLocalEngine())
+ if (IsLocalEngine())
{
- return this.options.SastSettings.LocalCodeEngine.Url + "/";
+ return options.SastSettings.LocalCodeEngine.Url + "/";
}
var endpoint = ResolveCustomEndpoint(this.options.CustomEndpoint);
- var uri = new Uri(endpoint);
-
- var result = uri.Scheme + "://" + uri.Host.Replace("api.", "deeproxy.").Replace("app.", "deeproxy.");
-
- if (!result.Contains("deeproxy."))
- {
- result = uri.Scheme + "://" + "deeproxy." + uri.Host;
- }
+ var result = GetCustomEndpointUrlFromSnykApi(endpoint, "deeproxy");
+
return result + "/";
}
- private bool IsSnykCodeAvailable(string endpointUrl)
- {
- var endpoint = ResolveCustomEndpoint(endpointUrl);
- var uri = new Uri(endpoint);
- return IsSaaS(uri) || IsSingleTenant(uri);
- }
-
///
/// Resolves the custom endpoint.
- /// If the endpointUrl is null or empty, then https://snyk.io/api" will be used.
+ /// If the endpointUrl is null or empty, then https://api.snyk.io" will be used.
///
private string ResolveCustomEndpoint(string endpointUrl)
{
var resolvedEndpoint = string.IsNullOrEmpty(endpointUrl)
- ? "https://snyk.io/api"
+ ? DefaultApiEndpoint
: endpointUrl.RemoveTrailingSlashes().Trim().ReplaceFirst("/v1", string.Empty);
return resolvedEndpoint;
}
- ///
- /// Checks if the deployment type is SaaS (production or development).
- ///
- private bool IsSaaS(Uri uri) =>
- !uri.Host.StartsWith("app") && uri.Host.EndsWith("snyk.io");
-
- ///
- /// Checks if the deployment type is Single Tenant.
- ///
- private bool IsSingleTenant(Uri uri) =>
- uri.Host.StartsWith("app") && uri.Host.EndsWith("snyk.io");
+ public static string GetCustomEndpointUrlFromSnykApi(string apiEndpoint, string subdomain)
+ {
+ const string regex = @"^(ap[pi]\.)?";
+ if (string.IsNullOrEmpty(subdomain))
+ throw new ArgumentException("subdomain must have a value to calculate the result endpoint");
+
+ if (string.IsNullOrEmpty(apiEndpoint) || !Uri.IsWellFormedUriString(apiEndpoint, UriKind.Absolute))
+ return string.Empty;
+
+ var endpointUri = new Uri(apiEndpoint);
+
+ var host = Regex.Replace(endpointUri.Host, regex, $"{subdomain}.");
+ var uriBuilder = new UriBuilder(endpointUri.Scheme, host);
+ return uriBuilder.ToString().RemoveTrailingSlashes();
+ }
private bool IsLocalEngine() => this.options.SastSettings?.LocalCodeEngineEnabled ?? false;
}
diff --git a/Snyk.VisualStudio.Extension.Shared/Settings/SnykGeneralOptionsDialogPage.cs b/Snyk.VisualStudio.Extension.Shared/Settings/SnykGeneralOptionsDialogPage.cs
index da65e73e8..6580059b3 100644
--- a/Snyk.VisualStudio.Extension.Shared/Settings/SnykGeneralOptionsDialogPage.cs
+++ b/Snyk.VisualStudio.Extension.Shared/Settings/SnykGeneralOptionsDialogPage.cs
@@ -1,21 +1,21 @@
-namespace Snyk.VisualStudio.Extension.Shared.Settings
+using System;
+using System.IO;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Security.Authentication;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+using Microsoft.VisualStudio.Shell;
+using Serilog;
+using Snyk.Common;
+using Snyk.Common.Authentication;
+using Snyk.Common.Service;
+using Snyk.Common.Settings;
+using Snyk.VisualStudio.Extension.Shared.Service;
+using Snyk.VisualStudio.Extension.Shared.UI.Notifications;
+
+namespace Snyk.VisualStudio.Extension.Shared.Settings
{
- using System;
- using System.IO;
- using System.Linq;
- using System.Runtime.InteropServices;
- using System.Security.Authentication;
- using System.Threading.Tasks;
- using System.Windows.Forms;
- using Microsoft.VisualStudio.Shell;
- using Serilog;
- using Snyk.Common;
- using Snyk.Common.Authentication;
- using Snyk.Common.Service;
- using Snyk.Common.Settings;
- using Snyk.VisualStudio.Extension.Shared.Service;
- using Snyk.VisualStudio.Extension.Shared.UI.Notifications;
-
///
/// Snyk general settings page.
///
@@ -23,14 +23,13 @@
[ComVisible(true)]
public class SnykGeneralOptionsDialogPage : DialogPage, ISnykOptions
{
-
- public String Application { get; set; }
- public String ApplicationVersion { get; set; }
- public String IntegrationName { get; } = SnykExtension.IntegrationName;
- public String IntegrationVersion { get; } = SnykExtension.Version;
- public String IntegrationEnvironment { get; set; }
- public String IntegrationEnvironmentVersion { get; set;}
-
+ public string Application { get; set; }
+ public string ApplicationVersion { get; set; }
+ public string IntegrationName { get; } = SnykExtension.IntegrationName;
+ public string IntegrationVersion { get; } = SnykExtension.Version;
+ public string IntegrationEnvironment { get; set; }
+ public string IntegrationEnvironmentVersion { get; set;}
+
private ISnykServiceProvider serviceProvider;
private SnykUserStorageSettingsService userStorageSettingsService;
@@ -117,9 +116,9 @@ public bool IsFedramp()
///
public bool IsAnalyticsPermitted()
{
- var endpointUri = new Uri(this.GetBaseAppURL());
+ var endpointUri = new Uri(this.GetBaseAppUrl());
- string[] permittedHosts = new string[] { "app.snyk.io", "app.us.snyk.io" };
+ var permittedHosts = new string[] { "app.snyk.io", "app.us.snyk.io" };
return permittedHosts.Contains(endpointUri.Host.ToLower());
}
@@ -153,7 +152,7 @@ public string CustomEndpoint
}
///
- public string SnykCodeSettingsUrl => $"{this.GetBaseAppURL()}/manage/snyk-code";
+ public string SnykCodeSettingsUrl => $"{this.GetBaseAppUrl()}/manage/snyk-code";
public SastSettings SastSettings
{
@@ -416,23 +415,14 @@ public bool Authenticate()
private void FireSettingsChangedEvent() => this.SettingsChanged?.Invoke(this, new SnykSettingsChangedEventArgs());
- private string GetBaseAppURL()
+ private string GetBaseAppUrl()
{
- var endpoint = this.customEndpoint.IsNullOrEmpty() ? "https://app.snyk.io" : this.customEndpoint.RemoveTrailingSlashes();
- Uri uri = new Uri(endpoint);
+ if (string.IsNullOrEmpty(customEndpoint))
+ return ApiEndpointResolver.DefaultAppEndpoint;
- if (!uri.Host.StartsWith("app") && (uri.Host.EndsWith("snyk.io") || uri.Host.EndsWith("snykgov.io")))
- {
- return endpoint.Replace("https://", "https://app.").RemoveFromEnd("/api");
- }
- else if (uri.Host.StartsWith("app") && (uri.Host.EndsWith("snyk.io") || uri.Host.EndsWith("snykgov.io")))
- {
- return endpoint.RemoveFromEnd("/api");
- }
- else
- {
- return "https://app.snyk.io";
- }
+ var result = ApiEndpointResolver.GetCustomEndpointUrlFromSnykApi(customEndpoint, "app");
+
+ return string.IsNullOrEmpty(result) ? ApiEndpointResolver.DefaultAppEndpoint : result;
}
private void ThrowFileNotFoundException()
diff --git a/Snyk.VisualStudio.Extension.Tests/GeneralOptionsDialogPage.cs b/Snyk.VisualStudio.Extension.Tests/GeneralOptionsDialogPage.cs
index 437b9d958..d98e73a53 100644
--- a/Snyk.VisualStudio.Extension.Tests/GeneralOptionsDialogPage.cs
+++ b/Snyk.VisualStudio.Extension.Tests/GeneralOptionsDialogPage.cs
@@ -30,12 +30,18 @@ public void ApiEndpointChanged_InvalidatesCliToken()
}
[Theory]
- [InlineData("https://app.snyk.io/api", true)]
[InlineData("https://snyk.io/api", true)]
+ [InlineData("https://app.snyk.io/api", true)]
[InlineData("https://app.us.snyk.io/api", true)]
[InlineData("https://app.eu.snyk.io/api", false)]
[InlineData("https://app.au.snyk.io/api", false)]
[InlineData("https://app.snykgov.io/api", false)]
+
+ [InlineData("https://api.snyk.io", true)]
+ [InlineData("https://api.us.snyk.io", true)]
+ [InlineData("https://api.eu.snyk.io", false)]
+ [InlineData("https://api.au.snyk.io", false)]
+ [InlineData("https://api.snykgov.io", false)]
public void IsAnalyticsPermitted(string endpoint, bool expected)
{
var optionsDialogPage = new SnykGeneralOptionsDialogPage();
@@ -53,7 +59,10 @@ public void IsAnalyticsPermitted(string endpoint, bool expected)
[InlineData("https://app.snyk.io/api", "https://app.snyk.io/manage/snyk-code")]
[InlineData("https://app.eu.snyk.io/api", "https://app.eu.snyk.io/manage/snyk-code")]
[InlineData("https://app.snykgov.io/api", "https://app.snykgov.io/manage/snyk-code")]
- [InlineData("https://example.org", "https://app.snyk.io/manage/snyk-code")]
+ [InlineData("https://api.snyk.io", "https://app.snyk.io/manage/snyk-code")]
+ [InlineData("https://api.snyk.io/", "https://app.snyk.io/manage/snyk-code")]
+ [InlineData("https://api.snykgov.io", "https://app.snykgov.io/manage/snyk-code")]
+ [InlineData("https://api.eu.snyk.io", "https://app.eu.snyk.io/manage/snyk-code")]
public void SnykCodeSettingsUrl(string endpoint, string expected)
{
var optionsDialogPage = new SnykGeneralOptionsDialogPage();